Skip to content

Commit 2fb97e8

Browse files
committed
race fix: m_on_cancel called after request finishes
This fixes a race condition in the mp.Context PassField() overload which is used to execute async requests, that can currently trigger segfaults as reported in bitcoin/bitcoin#34782 when a cancellation happens after the request executes but before it returns. The bug can be reproduced by running the unit test added in the previous commit and was also seen in antithesis (see details in linked issue), but should be unlikely to happen normally because the cancellation would have to happen in a very short window for there to be a problem. This bug was introduced commit in 0174450 which started to cancel requests on disconnects. Before that commit a cancellation callback was not present. This fix was originally posted in bitcoin/bitcoin#34782 (comment)
1 parent 846a43a commit 2fb97e8

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

include/mp/type-context.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ auto PassField(Priority<1>, TypeList<>, ServerContext& server_context, const Fn&
153153
// the disconnect handler trying to destroy the thread
154154
// client object.
155155
server.m_context.loop->sync([&] {
156+
// Clear cancellation callback. At this point the
157+
// method invocation finished and the result is
158+
// either being returned, or discarded if a
159+
// cancellation happened. So we do not need to be
160+
// notified of cancellations after this point. Also
161+
// we do not want to be notified because
162+
// cancel_mutex and server_context could be out of
163+
// scope when it happens.
164+
cancel_monitor.m_on_cancel = nullptr;
156165
auto self_dispose{kj::mv(self)};
157166
if (erase_thread) {
158167
// Look up the thread again without using existing

0 commit comments

Comments
 (0)