-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible deadlock when a waker is replaced #5429
Comments
I'll give it a try |
I'm thinking that a good solution might be the following: Trigger: Response: What are your thoughts on it? Would this be a good approach? |
What you've proposed seems like a way to modify the examples of deadlocking code from the issue description. These examples are only meant to demonstrate the problem which lies within Tokio's internal code. I would like to address this issue by changing the code in Tokio so that such deadlocks are impossible to trigger from a program using Tokio as a library. To resolve this issue, I would suggest you the following approach:
|
Why are we asserting that the future has to be pending, in the Notify test?
|
That assert is quite arbitrary, I am uncertain whether it is correct if the code does not deadlock. It was just quicker for me to write the examples that way. Surely you can ignore the result from |
Closing a semaphore is another instance of this. |
Reopening as it seems this issue got closed on accident (there is still the problem with closing a |
What do you mean with |
I mean the |
Should this issue be closed? It looks like BatchSemaphore has been fixed as well. |
Yes, thank you for pointing that out. |
Version
1.25.0
Description
There are some types in
tokio::sync
which keep a shared state behind a mutex and expose methods to modify it through a shared reference. For example:Notify::notify_waiters(&self)
,Semaphore::add_permits(&self, n: usize)
.It is possible to trigger a deadlock with custom wakers backed by
ArcWake
, which call those methods in their destructors. This can happen because tokio drops a waker while holding the lock to the shared state, and the waker tries to re-enter the lock in its Drop impl. Examples of wakers dropped with the lock held:Notify::notified
,Semaphore::acquire
.To trigger a deadlock, you can poll a future twice with two different wakers. At the second poll, the old waker will be replaced and instantly dropped. Examples of deadlocking code:
Notify::notified
Adapted from this test
Semaphore::acquire
This issue has been partially addressed in the past (#401, PR discussion), but only about calling
waker.wake()
while holding a lock, not dropping a waker in general.Simple solution
When an old waker has to be replaced, it can be stored on the side and dropped outside the critical section.
The text was updated successfully, but these errors were encountered: