Skip to content

Commit db172de

Browse files
authored
Fix bad assembly when a nested exported type is marked via link.xml (#107945)
When a nested exported type is marked via link.xml and the declaring type is not marked, cecil will write out an invalid exported type table which will lead to exceptions such as ``` System.ArgumentOutOfRangeException : Specified argument was out of the range of valid values. at Mono.Collections.Generic.Collection`1.get_Item(Int32 index) at Mono.Cecil.MetadataReader.ReadExportedTypes() at Mono.Cecil.ModuleDefinition.<>c.<get_ExportedTypes>b__116_0(ModuleDefinition _, MetadataReader reader) at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TRet& variable, TItem item, Func`3 read) at Mono.Cecil.ModuleDefinition.get_ExportedTypes() at Mono.Cecil.MetadataResolver.GetType(ModuleDefinition module, TypeReference reference) at Mono.Cecil.MetadataResolver.Resolve(TypeReference type) at Mono.Linker.Tests.TestCasesRunner.TestResolver.TryResolve(TypeReference typeReference) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\test\Trimming.Tests.Shared\TestResolver.cs:line 12 at Mono.Linker.ModuleDefinitionExtensions.ResolveType(ModuleDefinition module, String typeFullName, ITryResolveMetadata resolver) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\src\linker\Linker\ModuleDefinitionExtensions.cs:line 50 at Mono.Linker.TypeNameResolver.<ResolveTypeName>g__GetSimpleTypeFromModule|6_0(TypeName typeName, ModuleDefinition module) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\src\linker\Linker\TypeNameResolver.cs:line 135 at Mono.Linker.TypeNameResolver.ResolveTypeName(AssemblyDefinition originalAssembly, TypeName typeName, List`1 typeResolutionRecords) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\src\linker\Linker\TypeNameResolver.cs:line 101 at Mono.Linker.TypeNameResolver.TryResolveTypeName(AssemblyDefinition assembly, String typeNameString, TypeReference& typeReference, List`1& typeResolutionRecords) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\src\linker\Linker\TypeNameResolver.cs:line 44 at Mono.Linker.Tests.TestCasesRunner.ResultChecker.VerifyLinkingOfOtherAssemblies(AssemblyDefinition original) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\test\Mono.Linker.Tests\TestCasesRunner\ResultChecker.cs:line 320 at Mono.Linker.Tests.TestCasesRunner.ResultChecker.Check(TrimmedTestCaseResult linkResult) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\test\Mono.Linker.Tests\TestCasesRunner\ResultChecker.cs:line 114 at Mono.Linker.Tests.TestCases.All.Run(TestCase testCase) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\test\Mono.Linker.Tests\TestCases\TestSuites.cs:line 305 at Mono.Linker.Tests.TestCases.All.TypeForwardingTests(TestCase testCase) in E:\UnitySrc\dev\unity-runtime-1\src\tools\illink\test\Mono.Linker.Tests\TestCases\TestSuites.cs:line 262 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) ``` Or if you were to try and open the linked `Forwarder.dll` without the fix in something like ILSpy, it would crash ILSpy. An easy way to fix this seems to be marking the declaring type.
1 parent 726903d commit db172de

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs

+12
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ void MarkAndPreserveAll (TypeDefinition type, XPathNavigator nav)
103103
protected override TypeDefinition? ProcessExportedType (ExportedType exported, AssemblyDefinition assembly, XPathNavigator nav)
104104
{
105105
_context.MarkingHelpers.MarkExportedType (exported, assembly.MainModule, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition (nav));
106+
107+
// If a nested exported type is marked, then the declaring type must also be marked otherwise cecil will write out an invalid exported type table
108+
// and anything that tries to read the assembly with cecil will crash
109+
if (exported.DeclaringType != null) {
110+
var currentType = exported.DeclaringType;
111+
while (currentType != null) {
112+
var parent = currentType.DeclaringType;
113+
_context.MarkingHelpers.MarkExportedType (currentType, assembly.MainModule, new DependencyInfo(DependencyKind.DeclaringType, currentType), GetMessageOriginForPosition (nav));
114+
currentType = parent;
115+
}
116+
}
117+
106118
return base.ProcessExportedType (exported, assembly, nav);
107119
}
108120

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
5+
#if INCLUDE_FORWARDERS
6+
[assembly: System.Runtime.CompilerServices.TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.TypeForwarding.Dependencies.ForwardedNestedTypeLibrary))]
7+
#endif
8+
9+
#if INCLUDE_REFERENCE_IMPL
10+
namespace Mono.Linker.Tests.Cases.TypeForwarding.Dependencies;
11+
12+
public class ForwardedNestedTypeLibrary
13+
{
14+
public class NestedOne
15+
{
16+
public class NestedTwo
17+
{
18+
public class NestedThree
19+
{
20+
}
21+
}
22+
}
23+
}
24+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
5+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
6+
7+
namespace Mono.Linker.Tests.Cases.TypeForwarding;
8+
9+
[SetupCompileBefore ("Forwarder.dll", new[] { "Dependencies/ForwardedNestedTypeLibrary.cs" }, defines: new[] { "INCLUDE_REFERENCE_IMPL" })]
10+
[SetupCompileBefore ("Implementation.dll", new[] { "Dependencies/ForwardedNestedTypeLibrary.cs" }, defines: new[] { "INCLUDE_REFERENCE_IMPL" })]
11+
[SetupCompileAfter ("Forwarder.dll", new[] { "Dependencies/ForwardedNestedTypeLibrary.cs" }, references: new[] { "Implementation.dll" }, defines: new[] { "INCLUDE_FORWARDERS" })]
12+
[SetupLinkerDescriptorFile("NestedTypeForwarder.xml")]
13+
[KeptAssembly("Forwarder.dll")]
14+
[KeptTypeInAssembly("Forwarder.dll", "Mono.Linker.Tests.Cases.TypeForwarding.Dependencies.ForwardedNestedTypeLibrary")]
15+
[KeptTypeInAssembly("Forwarder.dll", "Mono.Linker.Tests.Cases.TypeForwarding.Dependencies.ForwardedNestedTypeLibrary/NestedOne")]
16+
[KeptTypeInAssembly("Forwarder.dll", "Mono.Linker.Tests.Cases.TypeForwarding.Dependencies.ForwardedNestedTypeLibrary/NestedOne/NestedTwo")]
17+
[KeptTypeInAssembly("Forwarder.dll", "Mono.Linker.Tests.Cases.TypeForwarding.Dependencies.ForwardedNestedTypeLibrary/NestedOne/NestedTwo/NestedThree")]
18+
public class NestedTypeForwarder
19+
{
20+
public static void Main ()
21+
{
22+
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<linker>
2+
<assembly fullname="Forwarder, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
3+
<type fullname="Mono.Linker.Tests.Cases.TypeForwarding.Dependencies.ForwardedNestedTypeLibrary/NestedOne/NestedTwo/NestedThree" preserve="all">
4+
</type>
5+
</assembly>
6+
</linker>

0 commit comments

Comments
 (0)