-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[release/8.0-staging] [mono] Fix deadlock in static constructor initialization #93943
Merged
lambdageek
merged 6 commits into
release/8.0-staging
from
backport/pr-93875-to-release/8.0-staging
Nov 14, 2023
Merged
[release/8.0-staging] [mono] Fix deadlock in static constructor initialization #93943
lambdageek
merged 6 commits into
release/8.0-staging
from
backport/pr-93875-to-release/8.0-staging
Nov 14, 2023
+243
−2
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
github-actions
bot
requested review from
vargaz,
lambdageek and
thaystg
as code owners
October 24, 2023 20:26
If two threads (A and B) need to call the static constructors for 3 classes X, Y, Z in this order: Thread A: X, Z, Y Thread B: Y, Z, X where the cctor for X in thread A invokes the cctor for Z and for Y, and the cctor for Y in thread B invokes the cctor for Z and X, then we can get into a situation where A and B both start the cctors for X and Y (so they will be in the type_initialization_hash for those two classes) and then both will try to init Z. In that case it could be that A will be responsible for initializing Z and B will block. Then A could finish initializing Z but B may not have woken up yet (and so it will be in blocked_thread_hash waiting for Z). At that point A (who is at this point already need to init Y) may think that it can wait for B to finish initializing Y. That is we get to `mono_coop_cond_timedwait (&lock->cond, &lock->mutex, timeout_ms)` with "lock" being the lock for `Y`. But in fact thread B will not be able to complete initializing Y because it will attempt to init X next - but meanwhile we did not indicate that thread A is blocked. As a result in thread A the timed wait will eventually timeout. And in this case we need to go back to the top and now correctly detect that A is waiting for Y and B is waiting for X. (At that point there is a cctor deadlock and ECMA rules allow one of the threads to return without calling the cctor) The old code here used to do an infinite wait: while (!lock->done) mono_coop_cond_wait (&lock->cond, &lock->mutex) This cannot succeed because "lock" (in thread A it's the lock for Y) will not be signaled since B (who is supposed to init Y) will instead block on the cctor for X. Fixes #93778
github-actions
bot
force-pushed
the
backport/pr-93875-to-release/8.0-staging
branch
from
October 25, 2023 12:54
1c22b4d
to
99b4d75
Compare
/azp run |
You have several pipelines (over 10) configured to build pull requests in this repository. Specify which pipelines you would like to run by using /azp run [pipelines] command. You can specify multiple pipelines using a comma separated list. |
Closed and reopened to re-run the CI because the base branch had a lot of wasm infra failures that have since been fixed. |
@vargaz can I get a review please |
simonrozsival
added
Servicing-consider
Issue for next servicing release review
and removed
Servicing-consider
Issue for next servicing release review
labels
Nov 8, 2023
Friendly reminder: If you'd like this to be included in the December release, please merge it before Tuesday November 14th EOD (Code Complete). |
vargaz
approved these changes
Nov 10, 2023
lambdageek
added
Servicing-approved
Approved for servicing release
and removed
Servicing-consider
Issue for next servicing release review
labels
Nov 14, 2023
Approved by tactics via email |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Backport of #93875 to release/8.0-staging
/cc @lambdageek
Fixes #93778
Customer Impact
Certain cyclic uses of static constructors (where a static constructor for one class may invoke a chain of static constructor calls that eventually require the static constructor of the original class to be called) between multiple threads that proceed in different order may cause the runtime to deadlock and for the app to become non-responsive. This affects mobile and WebAssembly apps.
Testing
Local testing and new CI tests
Risk
Medium. This PR replaces a concurrent wait without a time limit by a time-limited wait that followed by restarting the search for a cycle between the static constructors. In principle, this should only affect code that was previously deadlocked (and that will now not deadlock). However it could also have some unforseen effect on static constructors that previously took a long time (longer than the newly-introduced timeout) - it is possible that the new mechanism may now allow concurrent execution that was not previously allowed. This may have lead to unexpected behavior in user apps or first- and third-party libraries and frameworks.