-
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
Fix locking around m_LoaderAllocatorReferences iteration #68336
Fix locking around m_LoaderAllocatorReferences iteration #68336
Conversation
The iteration that marks loader allocators in LoaderAllocator::Mark() was not being called under an appropriate lock, which lead to a rare and hard to reproduce race condition and a crash in the LoaderAllocator::Mark(). The issue happened when the m_LoaderAllocatorReferences.Begin() returned an iterator at the time the m_LoaderAllocatorReferences were empty and another thread has written something into those references before the m_LoaderAllocatorReferences.End() was called. The iter was then evaluated as not equal to the End and the iter was getting dereferenced. Since the iterator had m_table set to NULL, the dereferencing caused crash.
@@ -384,6 +384,7 @@ LoaderAllocator * LoaderAllocator::GCLoaderAllocators_RemoveAssemblies(AppDomain | |||
AppDomain::AssemblyIterator i; | |||
// Iterate through every loader allocator, marking as we go | |||
{ | |||
CrstHolder chLoaderAllocatorReferencesLock(pAppDomain->GetLoaderAllocatorReferencesLock()); | |||
CrstHolder chAssemblyListLock(pAppDomain->GetAssemblyListLock()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second iteration below is going to acquire same locks now. We can acquire the locks just once for the whole duration of both iterations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I'll update the PR that way.
(setting the milestone to |
This change ports two unloadability fixes for issues found by a customer. * dotnet#68550 that adds reference between native `LoaderAllocator`s of two collectible `AssemblyLoadContexts` when one of them is used to resolve assembly using the other one. This reference ensures that the one that provides the resolved `Assembly` isn't collected before the one that uses it. * dotnet#68336 that adds a missing lock around `m_LoaderAllocatorReferences` iteration during assembly load context destruction.
* [Release/6.0] Port unloadability fixes This change ports two unloadability fixes for issues found by a customer. * #68550 that adds reference between native `LoaderAllocator`s of two collectible `AssemblyLoadContexts` when one of them is used to resolve assembly using the other one. This reference ensures that the one that provides the resolved `Assembly` isn't collected before the one that uses it. * #68336 that adds a missing lock around `m_LoaderAllocatorReferences` iteration during assembly load context destruction. * Remove breaking change part The change in main has added an exception in case a collectible `Assembly` is resolved into a non-collectible `AssemblyLoadContext`. Although that is incorrect, there are cases when it would work. So the added exception is a breaking change that I think we likely don't want to get into 6.0
The iteration that marks loader allocators in LoaderAllocator::Mark()
was not being called under an appropriate lock, which lead to a rare and
hard to reproduce race condition and a crash in the
LoaderAllocator::Mark(). The issue happened when the
m_LoaderAllocatorReferences.Begin() returned an iterator at the time the
m_LoaderAllocatorReferences were empty and another thread has written
something into those references before the
m_LoaderAllocatorReferences.End() was called. The iter was then
evaluated as not equal to the End and the iter was getting dereferenced.
Since the iterator had m_table set to NULL, the dereferencing caused
crash.
The issue shows up as something like this: