Fix collectible AssemblyLoadContext weak handle (dotnet/coreclr#22193)
authorJan Vorlicek <janvorli@microsoft.com>
Fri, 25 Jan 2019 01:34:39 +0000 (02:34 +0100)
committerGitHub <noreply@github.com>
Fri, 25 Jan 2019 01:34:39 +0000 (02:34 +0100)
Native runtime keeps short weak handle for collectible AssemblyLoadContext
until the unload time when it gets converted to a strong one. A test
running with gc stress has recently hit a problem caused by the fact
that the weak handle is "short weak" and thus doesn't track
resurrection. Here is what happened:
* The test code has lost reference to the AssemblyLoadContext
* Finalizer was just invoked on that context due to that and so the weak
  short handle was destroyed.
* Native runtime called AssemblyLoadContext.Resolve with the now dead
  handle, the function tried to get the managed object and failed.

The fix is to change the handle type to long weak so that it doesn't get
destroyed before the finalization.

Commit migrated from https://github.com/dotnet/coreclr/commit/65918165dbeb24861f27fc96f0ccf380b13097d3

src/coreclr/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs
src/coreclr/src/binder/clrprivbinderassemblyloadcontext.cpp

index fdb27d9..38c1afc 100644 (file)
@@ -72,8 +72,8 @@ namespace System.Runtime.Loader
                     throw new InvalidOperationException(SR.GetResourceString("AssemblyLoadContext_Constructor_CannotInstantiateWhileUnloading"));
                 }
 
-                // If this is a collectible ALC, we are creating a weak handle otherwise we use a strong handle
-                var thisHandle = GCHandle.Alloc(this, IsCollectible ? GCHandleType.Weak : GCHandleType.Normal);
+                // If this is a collectible ALC, we are creating a weak handle tracking resurrection otherwise we use a strong handle
+                var thisHandle = GCHandle.Alloc(this, IsCollectible ? GCHandleType.WeakTrackResurrection : GCHandleType.Normal);
                 var thisHandlePtr = GCHandle.ToIntPtr(thisHandle);
                 m_pNativeAssemblyLoadContext = InitializeAssemblyLoadContext(thisHandlePtr, fRepresentsTPALoadContext, isCollectible);
 
index 6f74626..415b2ff 100644 (file)
@@ -266,7 +266,7 @@ void CLRPrivBinderAssemblyLoadContext::PrepareForLoadContextRelease(INT_PTR ptrM
     // CLRPrivBinderAssemblyLoadContext::ReleaseLoadContext is called.
     OBJECTHANDLE handle = reinterpret_cast<OBJECTHANDLE>(m_ptrManagedAssemblyLoadContext);
     OBJECTHANDLE strongHandle = reinterpret_cast<OBJECTHANDLE>(ptrManagedStrongAssemblyLoadContext);
-    DestroyShortWeakHandle(handle);
+    DestroyLongWeakHandle(handle);
     m_ptrManagedAssemblyLoadContext = reinterpret_cast<INT_PTR>(strongHandle);
 
     _ASSERTE(m_pAssemblyLoaderAllocator != NULL);