Skip to content

Commit bb74a97

Browse files
authored
Fix corlib module self reference (SamboyCoding#431)
* Fix corlib module self-reference * Remove zero checks
1 parent 582c58c commit bb74a97

File tree

3 files changed

+338
-4
lines changed

3 files changed

+338
-4
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using AsmResolver;
6+
using AsmResolver.DotNet;
7+
using AsmResolver.DotNet.Builder;
8+
using AsmResolver.DotNet.Signatures;
9+
using Cpp2IL.Core.OutputFormats;
10+
11+
namespace Cpp2IL.Core.Tests;
12+
13+
public class DllOutputTests
14+
{
15+
[Test]
16+
public void AllAssembliesBuild()
17+
{
18+
var appContext = GameLoader.LoadSimpleGame();
19+
20+
var assemblies = new AsmResolverDllOutputFormatDefault().BuildAssemblies(appContext);
21+
22+
using (Assert.EnterMultipleScope())
23+
{
24+
foreach (var assembly in assemblies)
25+
{
26+
Assert.DoesNotThrow(() =>
27+
{
28+
using MemoryStream stream = new();
29+
assembly.WriteManifest(stream, new ManagedPEImageBuilder(ThrowErrorListener.Instance));
30+
});
31+
}
32+
}
33+
}
34+
35+
[Test]
36+
public void MscorlibIsItsOwnCorLib()
37+
{
38+
var appContext = GameLoader.LoadSimpleGame();
39+
40+
var assemblies = new AsmResolverDllOutputFormatEmpty().BuildAssemblies(appContext);
41+
42+
var mscorlib = assemblies.First(a => a.Name == "mscorlib").ManifestModule!;
43+
44+
Assert.That(SignatureComparer.Default.Equals(mscorlib.CorLibTypeFactory.CorLibScope, mscorlib));
45+
}
46+
47+
[Test]
48+
public void MscorlibHasNoAssemblyReferences()
49+
{
50+
var appContext = GameLoader.LoadSimpleGame();
51+
52+
var assemblies = new AsmResolverDllOutputFormatEmpty().BuildAssemblies(appContext);
53+
54+
var mscorlib = assemblies.First(a => a.Name == "mscorlib").ManifestModule!;
55+
56+
Assert.That(mscorlib.AssemblyReferences, Is.Empty);
57+
}
58+
59+
[Test]
60+
public void MscorlibHasNoTypeReferences()
61+
{
62+
var appContext = GameLoader.LoadSimpleGame();
63+
64+
var assemblies = new AsmResolverDllOutputFormatEmpty().BuildAssemblies(appContext);
65+
66+
var mscorlib = assemblies.First(a => a.Name == "mscorlib").ManifestModule!;
67+
68+
SearchForTypeReference(mscorlib);
69+
}
70+
71+
private static void SearchForTypeReference(ModuleDefinition module)
72+
{
73+
if (ContainsTypeReference(module.CustomAttributes))
74+
{
75+
Assert.Fail($"Module {module} contains a type reference in its custom attributes");
76+
}
77+
if (ContainsTypeReference(module.Assembly?.CustomAttributes))
78+
{
79+
Assert.Fail($"Module {module} contains a type reference in its assembly custom attributes");
80+
}
81+
foreach (var typeDefinition in module.GetAllTypes())
82+
{
83+
// Type
84+
{
85+
if (ContainsTypeReference(typeDefinition.BaseType))
86+
{
87+
Assert.Fail($"Type {typeDefinition} contains a type reference in its base type");
88+
}
89+
if (ContainsTypeReference(typeDefinition.Interfaces.Select(i => i.Interface)))
90+
{
91+
Assert.Fail($"Type {typeDefinition} contains a type reference in its interfaces");
92+
}
93+
if (ContainsTypeReference(typeDefinition.GenericParameters.SelectMany(g => g.Constraints).Select(c => c.Constraint)))
94+
{
95+
Assert.Fail($"Type {typeDefinition} contains a type reference in its generic parameter constraints");
96+
}
97+
foreach (var methodOverride in typeDefinition.MethodImplementations)
98+
{
99+
if (methodOverride.Body is not MethodDefinition)
100+
{
101+
Assert.Fail($"Method override {methodOverride} in type {typeDefinition} does not have a method body");
102+
}
103+
if (ContainsTypeReference(methodOverride.Declaration?.Signature?.ReturnType))
104+
{
105+
Assert.Fail($"Method override {methodOverride} in type {typeDefinition} contains a type reference in its return type");
106+
}
107+
if (ContainsTypeReference(methodOverride.Declaration?.Signature?.ParameterTypes))
108+
{
109+
Assert.Fail($"Method override {methodOverride} in type {typeDefinition} contains a type reference in its parameter types");
110+
}
111+
if (methodOverride.Declaration is MethodSpecification methodSpecification && ContainsTypeReference(methodSpecification.Method?.Signature))
112+
{
113+
Assert.Fail($"Method override {methodOverride} in type {typeDefinition} contains a type reference in its method specification");
114+
}
115+
}
116+
if (ContainsTypeReference(typeDefinition.CustomAttributes))
117+
{
118+
Assert.Fail($"Type {typeDefinition} contains a type reference in its custom attributes");
119+
}
120+
}
121+
foreach (var field in typeDefinition.Fields)
122+
{
123+
if (ContainsTypeReference(field.Signature?.FieldType))
124+
{
125+
Assert.Fail($"Field {field} in type {typeDefinition} contains a type reference in its field type");
126+
}
127+
if (ContainsTypeReference(field.CustomAttributes))
128+
{
129+
Assert.Fail($"Field {field} in type {typeDefinition} contains a type reference in its custom attributes");
130+
}
131+
}
132+
foreach (var property in typeDefinition.Properties)
133+
{
134+
if (ContainsTypeReference(property.Signature?.ReturnType))
135+
{
136+
Assert.Fail($"Property {property} in type {typeDefinition} contains a type reference in its return type");
137+
}
138+
if (ContainsTypeReference(property.Signature?.ParameterTypes))
139+
{
140+
Assert.Fail($"Property {property} in type {typeDefinition} contains a type reference in its parameter types");
141+
}
142+
if (ContainsTypeReference(property.CustomAttributes))
143+
{
144+
Assert.Fail($"Property {property} in type {typeDefinition} contains a type reference in its custom attributes");
145+
}
146+
}
147+
foreach (var @event in typeDefinition.Events)
148+
{
149+
if (ContainsTypeReference(@event.EventType))
150+
{
151+
Assert.Fail($"Event {@event} in type {typeDefinition} contains a type reference in its event type");
152+
}
153+
if (ContainsTypeReference(@event.CustomAttributes))
154+
{
155+
Assert.Fail($"Event {@event} in type {typeDefinition} contains a type reference in its custom attributes");
156+
}
157+
158+
}
159+
foreach (var method in typeDefinition.Methods)
160+
{
161+
if (ContainsTypeReference(method.Signature?.ReturnType))
162+
{
163+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its return type");
164+
}
165+
if (ContainsTypeReference(method.Signature?.ParameterTypes))
166+
{
167+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its parameter types");
168+
}
169+
if (ContainsTypeReference(method.GenericParameters.SelectMany(g => g.Constraints).Select(c => c.Constraint)))
170+
{
171+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its generic parameter constraints");
172+
}
173+
if (ContainsTypeReference(method.CilMethodBody?.LocalVariables.Select(v => v.VariableType)))
174+
{
175+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its local variables");
176+
}
177+
if (ContainsTypeReference(method.CilMethodBody?.Instructions.Select(i => i.Operand as ITypeDefOrRef)))
178+
{
179+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its instructions");
180+
}
181+
if (ContainsTypeReference(method.CilMethodBody?.ExceptionHandlers.Select(h => h.ExceptionType)))
182+
{
183+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its exception handlers");
184+
}
185+
if (ContainsTypeReference(method.CustomAttributes))
186+
{
187+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its custom attributes");
188+
}
189+
if (ContainsTypeReference(method.ParameterDefinitions.SelectMany(p => p.CustomAttributes)))
190+
{
191+
Assert.Fail($"Method {method} in type {typeDefinition} contains a type reference in its parameter custom attributes");
192+
}
193+
}
194+
}
195+
}
196+
197+
private static bool ContainsTypeReference(IEnumerable<CustomAttribute>? customAttributes)
198+
{
199+
return customAttributes is not null && customAttributes.Any(ContainsTypeReference);
200+
}
201+
202+
private static bool ContainsTypeReference(MethodSignature? methodSignature)
203+
{
204+
return ContainsTypeReference(methodSignature?.ReturnType)
205+
|| ContainsTypeReference(methodSignature?.ParameterTypes);
206+
}
207+
208+
private static bool ContainsTypeReference(CustomAttribute customAttribute)
209+
{
210+
return ContainsTypeReference(customAttribute.Constructor?.Signature) || ContainsTypeReference(customAttribute.Signature);
211+
}
212+
213+
private static bool ContainsTypeReference(CustomAttributeSignature? signature)
214+
{
215+
if (signature is null)
216+
return false;
217+
218+
return ContainsTypeReference(signature.FixedArguments.Select(a => a.ArgumentType))
219+
|| ContainsTypeReference(signature.NamedArguments.Select(a => a.ArgumentType))
220+
|| ContainsTypeReference(signature.NamedArguments.Select(a => a.Argument.ArgumentType));
221+
}
222+
223+
private static bool ContainsTypeReference(TypeSignature? type)
224+
{
225+
return type switch
226+
{
227+
CorLibTypeSignature corLibTypeSignature => corLibTypeSignature.Scope is not ModuleDefinition,
228+
TypeDefOrRefSignature typeDefOrRefSignature => typeDefOrRefSignature.Type is not TypeDefinition,
229+
CustomModifierTypeSignature customModifierTypeSignature => ContainsTypeReference(customModifierTypeSignature.BaseType) || ContainsTypeReference(customModifierTypeSignature.ModifierType),
230+
TypeSpecificationSignature typeSpecificationSignature => ContainsTypeReference(typeSpecificationSignature.BaseType),
231+
GenericInstanceTypeSignature genericInstanceTypeSignature => ContainsTypeReference(genericInstanceTypeSignature.GenericType) || ContainsTypeReference(genericInstanceTypeSignature.TypeArguments),
232+
FunctionPointerTypeSignature functionPointerTypeSignature => ContainsTypeReference(functionPointerTypeSignature.Signature),
233+
_ => false, // null, GenericParameterSignature, SentinelTypeSignature
234+
};
235+
}
236+
237+
private static bool ContainsTypeReference(IEnumerable<TypeSignature?>? types)
238+
{
239+
return types is not null && types.Any(ContainsTypeReference);
240+
}
241+
242+
private static bool ContainsTypeReference(ITypeDefOrRef? typeDefOrRef)
243+
{
244+
return typeDefOrRef switch
245+
{
246+
null => false,
247+
InvalidTypeDefOrRef => true,
248+
TypeDefinition => false,
249+
TypeReference => true,
250+
TypeSpecification typeSpecification => ContainsTypeReference(typeSpecification.Signature),
251+
_ => throw new NotSupportedException(),
252+
};
253+
}
254+
255+
private static bool ContainsTypeReference(IEnumerable<ITypeDefOrRef?>? types)
256+
{
257+
return types is not null && types.Any(ContainsTypeReference);
258+
}
259+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Linq;
2+
using AsmResolver.DotNet;
3+
using AsmResolver.DotNet.Signatures;
4+
using Cpp2IL.Core.OutputFormats;
5+
using Cpp2IL.Core.Utils.AsmResolver;
6+
7+
namespace Cpp2IL.Core.Tests;
8+
9+
public class PrimitiveTests
10+
{
11+
[Test]
12+
public void PrimitiveTypesAreCorLibTypeSignature()
13+
{
14+
var appContext = GameLoader.LoadSimpleGame();
15+
16+
var assemblies = new AsmResolverDllOutputFormatEmpty().BuildAssemblies(appContext);
17+
18+
var mscorlib = assemblies.First(a => a.Name == "mscorlib").ManifestModule!;
19+
var notMscorlib = assemblies.First(a => a.Name != "mscorlib").ManifestModule!;
20+
21+
using (Assert.EnterMultipleScope())
22+
{
23+
Assert.That(appContext.SystemTypes.SystemByteType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
24+
Assert.That(appContext.SystemTypes.SystemSByteType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
25+
Assert.That(appContext.SystemTypes.SystemInt16Type.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
26+
Assert.That(appContext.SystemTypes.SystemUInt16Type.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
27+
Assert.That(appContext.SystemTypes.SystemInt32Type.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
28+
Assert.That(appContext.SystemTypes.SystemUInt32Type.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
29+
Assert.That(appContext.SystemTypes.SystemInt64Type.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
30+
Assert.That(appContext.SystemTypes.SystemUInt64Type.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
31+
Assert.That(appContext.SystemTypes.SystemSingleType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
32+
Assert.That(appContext.SystemTypes.SystemDoubleType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
33+
Assert.That(appContext.SystemTypes.SystemIntPtrType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
34+
Assert.That(appContext.SystemTypes.SystemUIntPtrType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
35+
Assert.That(appContext.SystemTypes.SystemBooleanType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
36+
Assert.That(appContext.SystemTypes.SystemCharType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
37+
Assert.That(appContext.SystemTypes.SystemStringType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
38+
Assert.That(appContext.SystemTypes.SystemObjectType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
39+
Assert.That(appContext.SystemTypes.SystemTypedReferenceType.ToTypeSignature(mscorlib) is CorLibTypeSignature { Scope: ModuleDefinition });
40+
41+
Assert.That(appContext.SystemTypes.SystemByteType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
42+
Assert.That(appContext.SystemTypes.SystemSByteType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
43+
Assert.That(appContext.SystemTypes.SystemInt16Type.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
44+
Assert.That(appContext.SystemTypes.SystemUInt16Type.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
45+
Assert.That(appContext.SystemTypes.SystemInt32Type.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
46+
Assert.That(appContext.SystemTypes.SystemUInt32Type.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
47+
Assert.That(appContext.SystemTypes.SystemInt64Type.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
48+
Assert.That(appContext.SystemTypes.SystemUInt64Type.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
49+
Assert.That(appContext.SystemTypes.SystemSingleType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
50+
Assert.That(appContext.SystemTypes.SystemDoubleType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
51+
Assert.That(appContext.SystemTypes.SystemIntPtrType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
52+
Assert.That(appContext.SystemTypes.SystemUIntPtrType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
53+
Assert.That(appContext.SystemTypes.SystemBooleanType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
54+
Assert.That(appContext.SystemTypes.SystemCharType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
55+
Assert.That(appContext.SystemTypes.SystemStringType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
56+
Assert.That(appContext.SystemTypes.SystemObjectType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
57+
Assert.That(appContext.SystemTypes.SystemTypedReferenceType.ToTypeSignature(notMscorlib) is CorLibTypeSignature { Scope: AssemblyReference });
58+
}
59+
}
60+
}

Cpp2IL.Core/OutputFormats/AsmResolverDummyDllOutputFormat.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ private List<AssemblyDefinition> BuildStubAssemblies(ApplicationAnalysisContext
166166
return ret;
167167
}
168168

169+
private sealed class CorLibModuleDefinition : ModuleDefinition
170+
{
171+
public CorLibModuleDefinition(string? name, AssemblyDefinition assembly) : base(name, new(assembly))
172+
{
173+
// https://github.com/Washi1337/AsmResolver/issues/620
174+
CorLibTypeFactory = new(this);
175+
AssemblyReferences.Clear();
176+
}
177+
}
178+
169179
private static AssemblyDefinition BuildStubAssembly(AssemblyAnalysisContext assemblyContext, AssemblyDefinition? corLib, IMetadataResolver metadataResolver)
170180
{
171181
var assemblyDefinition = assemblyContext.Definition;
@@ -196,10 +206,15 @@ private static AssemblyDefinition BuildStubAssembly(AssemblyAnalysisContext asse
196206
if (moduleName == "__Generated")
197207
moduleName += ".dll"; //__Generated doesn't have a .dll extension in the metadata but it is still of course a DLL
198208

199-
var managedModule = new ModuleDefinition(moduleName, new(corLib ?? ourAssembly)) //Use either ourself as corlib, if we are corlib, otherwise the provided one
200-
{
201-
MetadataResolver = metadataResolver
202-
};
209+
var managedModule = corLib is not null //Use either ourself as corlib, if we are corlib, otherwise the provided one
210+
? new ModuleDefinition(moduleName, new(corLib))
211+
{
212+
MetadataResolver = metadataResolver
213+
}
214+
: new CorLibModuleDefinition(moduleName, ourAssembly)
215+
{
216+
MetadataResolver = metadataResolver
217+
};
203218
ourAssembly.Modules.Add(managedModule);
204219

205220
foreach (var il2CppTypeDefinition in assemblyContext.TopLevelTypes)

0 commit comments

Comments
 (0)