-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Coroutines debugger may overwrite the actual state of coroutine during asynchronous resume #3193
Comments
Steps to reproduce:
|
qwwdfsad
added a commit
that referenced
this issue
Oct 31, 2022
### Reproducing scenario For the following code: ``` suspend fun foo() = yield() ``` the following bytecode is produced: ``` fun foo(...) { uCont.intercepted().dispatchUsingDispatcher() // 1 probeCoroutineSuspended() // 2 return COROUTINE_SUSPENDED // Unroll the stack } ``` And it is possible to observe the next 'probeCoroutineSuspended' **prior** to receiving 'probeCoroutineSuspended'. To address this, a dedicated 'unmatchedResumes' field is introduced to coroutine state, which keeps track of consecutive 'probeCoroutineResumed' without matching 'probeCoroutineSuspended' and attributes lately arrived probes to it. Unfortunately, it introduces a much more unlikely race when **two** 'probeCoroutineSuspended' are reordered, then we misattribute 'lastObservedFrame', but it is still better than misattribute actual coroutine state. @volatile and @synchronized are also introduced to DebugCoroutineInfoImpl as previously they have been a subject to data-races as well Fixes #3193
qwwdfsad
added a commit
that referenced
this issue
Oct 31, 2022
For the following code: ``` suspend fun foo() = yield() ``` the following bytecode is produced: ``` fun foo(...) { uCont.intercepted().dispatchUsingDispatcher() // 1 probeCoroutineSuspended() // 2 return COROUTINE_SUSPENDED // Unroll the stack } ``` And it is possible to observe the next 'probeCoroutineSuspended' **prior** to receiving 'probeCoroutineSuspended'. ### Steps taken To address this, a dedicated 'unmatchedResumes' field is introduced to the coroutine state, which keeps track of consecutive 'probeCoroutineResumed' without matching 'probeCoroutineSuspended' and attributes lately arrived probes to it. Unfortunately, it introduces a much more unlikely race when **two** 'probeCoroutineSuspended' are reordered, then we misattribute 'lastObservedFrame', but it is still better than misattributing the actual coroutine state. @volatile and @synchronized are also introduced to DebugCoroutineInfoImpl as previously they have been subject to data races as well Fixes #3193
qwwdfsad
added a commit
that referenced
this issue
Feb 2, 2023
### Reproducing scenario For the following code: ``` suspend fun foo() = yield() ``` the following bytecode is produced: ``` fun foo(...) { uCont.intercepted().dispatchUsingDispatcher() // 1 probeCoroutineSuspended() // 2 return COROUTINE_SUSPENDED // Unroll the stack } ``` And it is possible to observe the next 'probeCoroutineSuspended' **prior** to receiving 'probeCoroutineSuspended'. ### Steps taken To address this, a dedicated 'unmatchedResumes' field is introduced to the coroutine state, which keeps track of consecutive 'probeCoroutineResumed' without matching 'probeCoroutineSuspended' and attributes lately arrived probes to it. Unfortunately, it introduces a much more unlikely race when **two** 'probeCoroutineSuspended' are reordered, then we misattribute 'lastObservedFrame', but it is still better than misattributing the actual coroutine state. @volatile and @synchronized are also introduced to DebugCoroutineInfoImpl as previously they have been subject to data races as well Fixes #3193
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Consider the following situation when the dispatcher in the context is multithreaded
It basically can be boiled down to the following pseudocode:
where
dispatch
concurrently invokesprobeCoroutineResumed
to notify the debugger the coroutine is actually executing right now.The problem is straightforward -- if timings are unlucky enough,
probeCoroutineResumed
can be invoked beforeprobeCoroutineSuspended
, withprobeCoroutineSuspended
overwriting the state and leaving it asSUSPENDED
The text was updated successfully, but these errors were encountered: