Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="SharedInterfaceImplementation.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LoaderLinkTest.Shared\LoaderLinkTest.Shared.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -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";
}
}
Original file line number Diff line number Diff line change
@@ -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; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Compile Include="ISharedInterface.cs" />
</ItemGroup>
</Project>
33 changes: 33 additions & 0 deletions src/libraries/System.Runtime.Loader/tests/LoaderLinkTest.cs
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<Compile Include="CustomTPALoadContext.cs" />
<Compile Include="ResourceAssemblyLoadContext.cs" />
<Compile Include="SatelliteAssemblies.cs" />
<Compile Include="LoaderLinkTest.cs" />
<EmbeddedResource Include="MainStrings*.resx" />
</ItemGroup>
<ItemGroup>
Expand All @@ -29,8 +30,10 @@
<ProjectReference Include="ContextualReflectionDependency\System.Runtime.Loader.Test.ContextualReflectionDependency.csproj" />
<ProjectReference Include="ReferencedClassLib\ReferencedClassLib.csproj" />
<ProjectReference Include="ReferencedClassLibNeutralIsSatellite\ReferencedClassLibNeutralIsSatellite.csproj" />
<ProjectReference Include="LoaderLinkTest.Shared\LoaderLinkTest.Shared.csproj" />
<ProjectReference Include="LoaderLinkTest.Dynamic\LoaderLinkTest.Dynamic.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(TargetOS)' == 'Browser'">
<WasmFilesToIncludeFromPublishDir Include="$(AssemblyName).dll" />
</ItemGroup>
</Project>
</Project>
3 changes: 2 additions & 1 deletion src/mono/mono/metadata/assembly-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
72 changes: 49 additions & 23 deletions src/mono/mono/metadata/assembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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;
}
}
Comment on lines +1741 to +1746
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok this part makes sense to me.


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) {
Expand Down Expand Up @@ -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) {
Expand Down