Skip to content

Commit d1993a8

Browse files
foriequal0tomusdrw
authored andcommitted
Fix race condition on wait() (#504)
Manually dropping the future passed from `Future::select` before sending `done_tx` prevents the race condition. `Future::select` pass the unresolved future, which is a `Server` holding `rpc_handler`, to the following callback. Therefore, it is dropped after the `done_tx.send(())` after the callback exits. It is possible that the thread that has executed `wait()`, which is usually the main thread, terminates before the thread sending `done_tx` drops `rpc_handler`. Static variables are destructed at the end of termination of the main thread, and then a segfault occurs when the thread dropping the rpc_handler accesses the variables.
1 parent 8ebb62d commit d1993a8

File tree

2 files changed

+10
-2
lines changed

2 files changed

+10
-2
lines changed

http/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,12 @@ fn serve<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>>(
566566
}))
567567
.map_err(|_| ())
568568
})
569-
.and_then(|_| done_tx.send(()))
569+
.and_then(|(_, server)| {
570+
// We drop the server first to prevent a situation where main thread terminates
571+
// before the server is properly dropped (see #504 for more details)
572+
drop(server);
573+
done_tx.send(())
574+
})
570575
});
571576
}
572577

ipc/src/server.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,10 @@ impl<M: Metadata, S: Middleware<M>> ServerBuilder<M, S> {
240240
.buffer_unordered(1024)
241241
.for_each(|_| Ok(()))
242242
.select(stop)
243-
.map(|_| {
243+
.map(|(_, server)| {
244+
// We drop the server first to prevent a situation where main thread terminates
245+
// before the server is properly dropped (see #504 for more details)
246+
drop(server);
244247
let _ = wait_signal.send(());
245248
})
246249
.map_err(|_| ()),

0 commit comments

Comments
 (0)