Make sure default ALC is initialized before resolving satellite assembly (#1032)
authorElinor Fung <47805090+elinor-fung@users.noreply.github.com>
Tue, 7 Jan 2020 01:26:10 +0000 (17:26 -0800)
committerGitHub <noreply@github.com>
Tue, 7 Jan 2020 01:26:10 +0000 (17:26 -0800)
src/coreclr/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
src/coreclr/src/binder/clrprivbindercoreclr.cpp
src/coreclr/src/vm/mscorlib.h
src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.DefaultProbing.cs

index 24cc945..5474d5b 100644 (file)
@@ -211,5 +211,13 @@ namespace System.Runtime.Loader
             // Don't use trace to TPL event source in ActivityTracker - that event source is a singleton and its instantiation may have triggered the load.
             ActivityTracker.Instance.OnStop(NativeRuntimeEventSource.Log.Name, AssemblyLoadName, 0, ref activityId, useTplSource: false);
         }
+
+        /// <summary>
+        /// Called by the runtime to make sure the default ALC is initialized
+        /// </summary>
+        private static void InitializeDefaultContext()
+        {
+            _ = AssemblyLoadContext.Default;
+        }
     }
 }
index 2025dda..f99fe46 100644 (file)
@@ -5,6 +5,7 @@
 #include "common.h"
 #include "assemblybinder.hpp"
 #include "clrprivbindercoreclr.h"
+#include "variables.hpp"
 
 using namespace BINDER_SPACE;
 
@@ -71,12 +72,29 @@ HRESULT CLRPrivBinderCoreCLR::BindAssemblyByName(IAssemblyName     *pIAssemblyNa
             // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
             //    mismatch (either due to version difference or strong-name difference).
             //
-            // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
-            // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
-            // that has been loaded.
-
-            // Attempt to resolve the assembly via managed TPA ALC instance if one exists
+            // Attempt to resolve the assembly via managed ALC instance. This can either fail the bind or return reference to an existing
+            // assembly that has been loaded
             INT_PTR pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
+            if (pManagedAssemblyLoadContext == NULL)
+            {
+                // For satellite assemblies, the managed ALC has additional resolution logic (defined by the runtime) which
+                // should be run even if the managed default ALC has not yet been used. (For non-satellite assemblies, any
+                // additional logic comes through a user-defined event handler which would have initialized the managed ALC,
+                // so if the managed ALC is not set yet, there is no additional logic to run)
+                SString &culture = pAssemblyName->GetCulture();
+                if (!culture.IsEmpty() && !culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
+                {
+                    // Make sure the managed default ALC is initialized.
+                    GCX_COOP();
+                    PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__INITIALIZE_DEFAULT_CONTEXT);
+                    DECLARE_ARGHOLDER_ARRAY(args, 0);
+                    CALL_MANAGED_METHOD_NORET(args)
+
+                    pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
+                    _ASSERTE(pManagedAssemblyLoadContext != NULL);
+                }
+            }
+
             if (pManagedAssemblyLoadContext != NULL)
             {
                 hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName, pIAssemblyName,
index bafcc27..e6c3ca0 100644 (file)
@@ -926,13 +926,14 @@ DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  RESOLVEUNMANAGEDDLL,           ResolveUnmana
 DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  RESOLVEUNMANAGEDDLLUSINGEVENT, ResolveUnmanagedDllUsingEvent, SM_Str_AssemblyBase_IntPtr_RetIntPtr)
 DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  RESOLVEUSINGEVENT,             ResolveUsingResolvingEvent,    SM_IntPtr_AssemblyName_RetAssemblyBase)
 DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  RESOLVESATELLITEASSEMBLY,      ResolveSatelliteAssembly,      SM_IntPtr_AssemblyName_RetAssemblyBase)
-DEFINE_FIELD(ASSEMBLYLOADCONTEXT,   ASSEMBLY_LOAD,          AssemblyLoad)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_ASSEMBLY_LOAD,       OnAssemblyLoad, SM_Assembly_RetVoid)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_RESOURCE_RESOLVE,    OnResourceResolve, SM_Assembly_Str_RetAssembly)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_TYPE_RESOLVE,        OnTypeResolve, SM_Assembly_Str_RetAssembly)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_ASSEMBLY_RESOLVE,    OnAssemblyResolve, SM_Assembly_Str_RetAssembly)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  START_ASSEMBLY_LOAD,    StartAssemblyLoad,    SM_RefGuid_RefGuid_RetVoid)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  STOP_ASSEMBLY_LOAD,     StopAssemblyLoad,     SM_RefGuid_RetVoid)
+DEFINE_FIELD(ASSEMBLYLOADCONTEXT,   ASSEMBLY_LOAD,              AssemblyLoad)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_ASSEMBLY_LOAD,           OnAssemblyLoad,             SM_Assembly_RetVoid)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_RESOURCE_RESOLVE,        OnResourceResolve,          SM_Assembly_Str_RetAssembly)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_TYPE_RESOLVE,            OnTypeResolve,              SM_Assembly_Str_RetAssembly)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  ON_ASSEMBLY_RESOLVE,        OnAssemblyResolve,          SM_Assembly_Str_RetAssembly)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  START_ASSEMBLY_LOAD,        StartAssemblyLoad,          SM_RefGuid_RefGuid_RetVoid)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  STOP_ASSEMBLY_LOAD,         StopAssemblyLoad,           SM_RefGuid_RetVoid)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT,  INITIALIZE_DEFAULT_CONTEXT, InitializeDefaultContext,   SM_RetVoid)
 
 #ifdef FEATURE_COMINTEROP
 DEFINE_CLASS(WINDOWSRUNTIMEMETATADA, WinRT, WindowsRuntimeMetadata)
index dcef9f7..7f594a4 100644 (file)
@@ -193,9 +193,6 @@ namespace BinderTracingTests
             AssemblyName assemblyName = new AssemblyName($"{SubdirectoryAssemblyName}.resources");
             assemblyName.CultureInfo = SatelliteCulture;
 
-            // https://github.com/dotnet/corefx/issues/42477
-            _ = AssemblyLoadContext.Default;
-
             Assembly OnAppDomainAssemblyResolve(object sender, ResolveEventArgs args)
             {
                 AssemblyName requested = new AssemblyName(args.Name);