diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 3979d76aeadb74..fe0b293e4e0139 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -105,6 +105,7 @@ public static void LoadFromAssemblyName_AssemblyNotFound() } [Fact] + [PlatformSpecific(~TestPlatforms.Browser)] // Corelib does not exist on disc for Browser builds public static void LoadFromAssemblyName_ValidTrustedPlatformAssembly() { var asmName = typeof(System.Linq.Enumerable).Assembly.GetName(); diff --git a/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Dynamic/LoaderLinkTest.Dynamic.csproj b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Dynamic/LoaderLinkTest.Dynamic.csproj new file mode 100644 index 00000000000000..7fdc93128a864e --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Dynamic/LoaderLinkTest.Dynamic.csproj @@ -0,0 +1,11 @@ + + + $(NetCoreAppCurrent) + + + + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Dynamic/SharedInterfaceImplementation.cs b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Dynamic/SharedInterfaceImplementation.cs new file mode 100644 index 00000000000000..3087d8a6daa9cf --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Dynamic/SharedInterfaceImplementation.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +using LoaderLinkTest.Shared; + +namespace LoaderLinkTest.Dynamic +{ + public class SharedInterfaceImplementation : ISharedInterface + { + public string TestString => "Hello"; + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Shared/ISharedInterface.cs b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Shared/ISharedInterface.cs new file mode 100644 index 00000000000000..3c381e1bc2d3c1 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Shared/ISharedInterface.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace LoaderLinkTest.Shared +{ + public interface ISharedInterface + { + string TestString { get; } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Shared/LoaderLinkTest.Shared.csproj b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Shared/LoaderLinkTest.Shared.csproj new file mode 100644 index 00000000000000..2adb5cb89d9747 --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.Shared/LoaderLinkTest.Shared.csproj @@ -0,0 +1,8 @@ + + + $(NetCoreAppCurrent) + + + + + diff --git a/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.cs b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.cs new file mode 100644 index 00000000000000..c7daa91333664a --- /dev/null +++ b/src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using Xunit; + +using LoaderLinkTest.Shared; + +namespace LoaderLinkTest +{ + public class LoaderLinkTest + { + [Fact] + public static void EnsureTypesLinked() // https://github.com/dotnet/runtime/issues/42207 + { + string parentDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + byte[] bytes = File.ReadAllBytes(Path.Combine(parentDir != null ? parentDir : "/", "LoaderLinkTest.Dynamic.dll")); + Assembly asm = Assembly.Load(bytes); + var dynamicType = asm.GetType("LoaderLinkTest.Dynamic.SharedInterfaceImplementation", true); + var sharedInterface = dynamicType.GetInterfaces().First(e => e.Name == nameof(ISharedInterface)); + Assert.Equal(typeof(ISharedInterface).Assembly, sharedInterface.Assembly); + Assert.Equal(typeof(ISharedInterface), sharedInterface); + + var instance = Activator.CreateInstance(dynamicType); + Assert.True(instance is ISharedInterface); + + Assert.NotNull(((ISharedInterface)instance).TestString); // cast should not fail + } + } +} diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index f43714d9365d9a..ae825641dab5e3 100644 --- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -14,6 +14,7 @@ + @@ -29,8 +30,10 @@ + + - \ No newline at end of file + diff --git a/src/mono/mono/metadata/assembly-internals.h b/src/mono/mono/metadata/assembly-internals.h index 29a3334c3315ce..486cfa3ed681ce 100644 --- a/src/mono/mono/metadata/assembly-internals.h +++ b/src/mono/mono/metadata/assembly-internals.h @@ -16,7 +16,8 @@ #else #define MONO_ASSEMBLY_CORLIB_NAME "System.Private.CoreLib" #endif -#define MONO_ASSEMBLY_CORLIB_RESOURCE_NAME (MONO_ASSEMBLY_CORLIB_NAME ".resources") +#define MONO_ASSEMBLY_RESOURCE_SUFFIX ".resources" +#define MONO_ASSEMBLY_CORLIB_RESOURCE_NAME (MONO_ASSEMBLY_CORLIB_NAME MONO_ASSEMBLY_RESOURCE_SUFFIX) /* Flag bits for mono_assembly_names_equal_flags (). */ typedef enum { diff --git a/src/mono/mono/metadata/assembly.c b/src/mono/mono/metadata/assembly.c index 973555e68e9125..931fe18e0883b6 100644 --- a/src/mono/mono/metadata/assembly.c +++ b/src/mono/mono/metadata/assembly.c @@ -1651,16 +1651,16 @@ load_reference_by_aname_individual_asmctx (MonoAssemblyName *aname, MonoAssembly } #else static MonoAssembly * -search_bundle_for_assembly (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, gboolean is_satellite) +search_bundle_for_assembly (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname) { - if ((bundles == NULL && !is_satellite) || (satellite_bundles == NULL && is_satellite)) + if (bundles == NULL && satellite_bundles == NULL) return NULL; MonoImageOpenStatus status; MonoImage *image; MonoAssemblyLoadRequest req; image = mono_assembly_open_from_bundle (alc, aname->name, &status, FALSE, aname->culture); - if (!image) { + if (!image && !g_str_has_suffix (aname->name, ".dll")) { char *name = g_strdup_printf ("%s.dll", aname->name); image = mono_assembly_open_from_bundle (alc, name, &status, FALSE, aname->culture); } @@ -1692,23 +1692,27 @@ netcore_load_reference (MonoAssemblyName *aname, MonoAssemblyLoadContext *alc, M * Try these until one of them succeeds (by returning a non-NULL reference): * 1. Check if it's already loaded by the ALC. * - * 2. If we have a bundle registered, search the images for a matching name. + * 2. If it's a non-default ALC, call the Load() method. * - * 3. If it's a non-default ALC, call the Load() method. - * - * 4. If the ALC is not the default and this is not a satellite request, + * 3. If the ALC is not the default and this is not a satellite request, * check if it's already loaded by the default ALC. * - * 5. If the ALC is the default or this is not a satellite request, + * 4. If we have a bundle registered and this is not a satellite request, + * search the images for a matching name. + * + * 5. If we have a satellite bundle registered and this is a satellite request, + * find the parent ALC and search the images for a matching name and culture. + * + * 6. If the ALC is the default or this is not a satellite request, * check the TPA list, APP_PATHS, and ApplicationBase. * - * 6. If this is a satellite request, call the ALC ResolveSatelliteAssembly method. + * 7. If this is a satellite request, call the ALC ResolveSatelliteAssembly method. * - * 7. Call the ALC Resolving event. + * 8. Call the ALC Resolving event. * - * 8. Call the ALC AssemblyResolve event (except for corlib satellite assemblies). + * 9. Call the ALC AssemblyResolve event (except for corlib satellite assemblies). * - * 9. Return NULL. + * 10. Return NULL. */ reference = mono_assembly_loaded_internal (alc, aname, FALSE); @@ -1717,14 +1721,6 @@ netcore_load_reference (MonoAssemblyName *aname, MonoAssemblyLoadContext *alc, M goto leave; } - if (bundles != NULL || satellite_bundles != NULL) { - reference = search_bundle_for_assembly (alc, aname, is_satellite); - if (reference) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly found in the bundle: '%s'.", aname->name); - goto leave; - } - } - if (!is_default) { reference = mono_alc_invoke_resolve_using_load_nofail (alc, aname); if (reference) { @@ -1741,6 +1737,38 @@ netcore_load_reference (MonoAssemblyName *aname, MonoAssemblyLoadContext *alc, M } } + if (bundles != NULL && !is_satellite) { + reference = search_bundle_for_assembly (mono_domain_default_alc (mono_alc_domain (alc)), aname); + if (reference) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly found in the bundle: '%s'.", aname->name); + goto leave; + } + } + + if (satellite_bundles != NULL && is_satellite) { + // Satellite assembly byname requests should be loaded in the same ALC as their parent assembly + size_t name_len = strlen (aname->name); + char *parent_name = NULL; + MonoAssemblyLoadContext *parent_alc = NULL; + if (g_str_has_suffix (aname->name, MONO_ASSEMBLY_RESOURCE_SUFFIX)) + parent_name = g_strdup_printf ("%s.dll", g_strndup (aname->name, name_len - strlen (MONO_ASSEMBLY_RESOURCE_SUFFIX))); + + if (parent_name) { + MonoAssemblyOpenRequest req; + mono_assembly_request_prepare_open (&req, MONO_ASMCTX_DEFAULT, alc); + MonoAssembly *parent_assembly = mono_assembly_request_open (parent_name, &req, NULL); + parent_alc = mono_assembly_get_alc (parent_assembly); + } + + if (parent_alc) + reference = search_bundle_for_assembly (parent_alc, aname); + + if (reference) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly found in the satellite bundle: '%s'.", aname->name); + goto leave; + } + } + if (is_default || !is_satellite) { reference = invoke_assembly_preload_hook (mono_domain_default_alc (mono_alc_domain (alc)), aname, assemblies_path); if (reference) { @@ -2593,11 +2621,9 @@ mono_assembly_open_from_bundle (MonoAssemblyLoadContext *alc, const char *filena #else gboolean is_satellite = culture && culture [0] != 0;; if (is_satellite) - { image = open_from_satellite_bundle (alc, filename, status, refonly, culture); - } else { + else image = open_from_bundle_internal (alc, filename, status, refonly, FALSE); - } #endif if (image) {