Skip to content

Commit f1c428a

Browse files
Protect against circular type forwarders (#806)
* Protect against circular type forwarders If we have two assemblies with type forwarders that point to each other, we enter an infinite loop and a stack overflow. This breaks the cycle by detecting reentrancy. Fixes #706 * Add a test for TypeForwardedTo circularity * Move field up
1 parent 5de7d8c commit f1c428a

File tree

4 files changed

+29
-1
lines changed

4 files changed

+29
-1
lines changed

Mono.Cecil/ExportedType.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public sealed class ExportedType : IMetadataTokenProvider {
2222
int identifier;
2323
ExportedType declaring_type;
2424
internal MetadataToken token;
25+
bool reentrancyGuard;
2526

2627
public string Namespace {
2728
get { return @namespace; }
@@ -227,7 +228,17 @@ public override string ToString ()
227228

228229
public TypeDefinition Resolve ()
229230
{
230-
return module.Resolve (CreateReference ());
231+
if (reentrancyGuard) {
232+
throw new InvalidOperationException ($"Circularity when resolving exported type: '{this}'");
233+
}
234+
235+
reentrancyGuard = true;
236+
try {
237+
return module.Resolve (CreateReference ());
238+
}
239+
finally {
240+
reentrancyGuard = false;
241+
}
231242
}
232243

233244
internal TypeReference CreateReference ()

Test/Mono.Cecil.Tests/ResolveTests.cs

+17
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,23 @@ public void TypeForwarder ()
148148
Assert.AreEqual (Platform.OnCoreClr ? "System.Private.CoreLib" : "mscorlib", definition.Module.Assembly.Name.Name);
149149
}
150150

151+
[Test]
152+
public void TypeForwarderCircularity ()
153+
{
154+
var resolver = new CustomResolver();
155+
var parameters = new ReaderParameters { AssemblyResolver = resolver };
156+
157+
var module1 = GetResourceModule("TypeForwarderLoop1.dll", parameters);
158+
var module2 = GetResourceModule("TypeForwarderLoop2.dll", parameters);
159+
160+
resolver.Register(module1.Assembly);
161+
resolver.Register(module2.Assembly);
162+
163+
var reference = new TypeReference("MyNamespace", "MyType", module1, AssemblyNameReference.Parse(module1.Assembly.FullName), false);
164+
165+
Assert.Throws<InvalidOperationException>(() => { _ = reference.Resolve(); });
166+
}
167+
151168
[Test]
152169
public void NestedTypeForwarder ()
153170
{
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)