Skip to content

UniversalEvent's race condition on cancellation #375

@x42005e1f

Description

@x42005e1f

UniversalEvent (and consequently UniversalResult) has a race condition in the _unblock_waiters() method. Since discarding a future object from the _waiting set is done without holding the lock[1][2][3], it may occur at iteration time in the _unblock_waiters() method. As a result, RuntimeError will be raised.

Since this is a multi-threaded issue, it cannot be reliably reproduced. Instead, below is synthetic code that demonstrates that behavior.

items = {1, 2, 3}

for item in items:  # raises RuntimeError
    items.discard(item + 1)

The quickest solution is to copy the set before iterating.

Note that this is actually #352. The fixes were not sufficient - they reduce the reproducibility of the issue, but they do not fix the issue itself. Getting a reference to the set and calling its method are different operations, and context switching can happen in between.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions