Skip to content

Commit bb6f737

Browse files
author
Vincent Rouillé
authored
Merge pull request #147 from Clikengo/fix-136-callback-segfault
fix #136: Segfault when pending future dropped
2 parents 1658f44 + f200474 commit bb6f737

File tree

2 files changed

+64
-7
lines changed

2 files changed

+64
-7
lines changed

foundationdb/src/future.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ use error::{self, Error, Result};
2626
/// An opaque type that represents a Future in the FoundationDB C API.
2727
pub(crate) struct FdbFuture {
2828
f: Option<*mut fdb::FDBFuture>,
29-
task: Option<Box<futures::task::Task>>,
29+
cb_active: bool,
3030
}
3131

3232
impl FdbFuture {
3333
// `new` is marked as unsafe because it's lifetime is not well-defined.
3434
pub(crate) unsafe fn new(f: *mut fdb::FDBFuture) -> Self {
3535
Self {
3636
f: Some(f),
37-
task: None,
37+
cb_active: false,
3838
}
3939
}
4040
}
@@ -56,14 +56,14 @@ impl futures::Future for FdbFuture {
5656
fn poll(&mut self) -> std::result::Result<Async<Self::Item>, Self::Error> {
5757
let f = self.f.expect("cannot poll after resolve");
5858

59-
if self.task.is_none() {
59+
if !self.cb_active {
6060
let task = futures::task::current();
6161
let task = Box::new(task);
62-
let task_ptr = task.as_ref() as *const _;
62+
let task_ptr = Box::into_raw(task);
6363
unsafe {
6464
fdb::fdb_future_set_callback(f, Some(fdb_future_callback), task_ptr as *mut _);
6565
}
66-
self.task = Some(task);
66+
self.cb_active = true;
6767

6868
return Ok(Async::NotReady);
6969
}
@@ -87,8 +87,7 @@ extern "C" fn fdb_future_callback(
8787
_f: *mut fdb::FDBFuture,
8888
callback_parameter: *mut ::std::os::raw::c_void,
8989
) {
90-
let task: *const futures::task::Task = callback_parameter as *const _;
91-
let task: &futures::task::Task = unsafe { &*task };
90+
let task = unsafe { Box::from_raw(callback_parameter as *mut futures::task::Task) };
9291
task.notify();
9392
}
9493

foundationdb/tests/future.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2019 foundationdb-rs developers, https://github.com/bluejekyll/foundationdb-rs/graphs/contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4+
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5+
// http://opensource.org/licenses/MIT>, at your option. This file may not be
6+
// copied, modified, or distributed except according to those terms.
7+
8+
extern crate foundationdb;
9+
extern crate futures;
10+
#[macro_use]
11+
extern crate lazy_static;
12+
13+
use crate::error::Result;
14+
use foundationdb::transaction::TrxGet;
15+
use foundationdb::*;
16+
use futures::prelude::*;
17+
18+
mod common;
19+
20+
struct AbortingFuture {
21+
inner: TrxGet,
22+
polled: bool,
23+
}
24+
25+
impl Future for AbortingFuture {
26+
type Item = ();
27+
type Error = Error;
28+
29+
fn poll(&mut self) -> Result<Async<Self::Item>> {
30+
// poll once only
31+
if !self.polled {
32+
self.polled = true;
33+
let _ = self.inner.poll();
34+
}
35+
36+
Ok(Async::Ready(()))
37+
}
38+
}
39+
40+
#[test]
41+
// dropping a future while it's in the pending state should not crash
42+
fn test_future_discard() {
43+
common::setup_static();
44+
45+
let db = Cluster::new(foundationdb::default_config_path())
46+
.and_then(|cluster| cluster.create_database())
47+
.wait()
48+
.unwrap();
49+
50+
for _i in 0..=1000 {
51+
db.transact(|trx| AbortingFuture {
52+
inner: trx.get(b"key", false),
53+
polled: false,
54+
})
55+
.wait()
56+
.unwrap();
57+
}
58+
}

0 commit comments

Comments
 (0)