Skip to content

Commit 58de60f

Browse files
authored
[generator] Handle Java class with base class set to itself. (#1032)
Fixes: #1031 There apparently exists a Java obfuscator that attempts to break tools by setting the base class of a class to itself. public class c5<BaseHandler> extends c5<BaseHandler> { // … } This breaks `generator` with a `StackOverflowException`: Stack overflow: IP: 0x11ae88918, fault addr: 0x30d984fd8 Stacktrace: at Java.Interop.Tools.JavaTypeSystem.Models.JavaClassModel.PrepareGenericInheritanceMapping () <...> at Java.Interop.Tools.JavaTypeSystem.Models.JavaClassModel.get_GenericInheritanceMapping () at Java.Interop.Tools.JavaTypeSystem.Models.JavaMethodModel/<>c__DisplayClass47_0.<FindBaseMethod>b__0 (Java.Interop.Tools.JavaTypeSystem.Models.JavaMethodModel) at System.Linq.Enumerable.TryGetFirst<TSource_REF> (System.Collections.Generic.IEnumerable`1<TSource_REF>,System.Func`2<TSource_REF, bool>,bool&) at System.Linq.Enumerable.FirstOrDefault<TSource_REF> (System.Collections.Generic.IEnumerable`1<TSource_REF>,System.Func`2<TSource_REF, bool>) at Java.Interop.Tools.JavaTypeSystem.Models.JavaMethodModel.FindBaseMethod (Java.Interop.Tools.JavaTypeSystem.Models.JavaClassModel) at Java.Interop.Tools.JavaTypeSystem.Models.JavaClassModel.ResolveBaseMembers ()k at Java.Interop.Tools.JavaTypeSystem.Models.JavaTypeCollection.ResolveCollection (Java.Interop.Tools.JavaTypeSystem.TypeResolutionOptions) at generator.JavaTypeResolutionFixups.Fixup (string,string,Java.Interop.Tools.Cecil.DirectoryAssemblyResolver,string[]) at Xamarin.Android.Binder.CodeGenerator.Run (Xamarin.Android.Binder.CodeGeneratorOptions,Java.Interop.Tools.Cecil.DirectoryAssemblyResolver) at Xamarin.Android.Binder.CodeGenerator.Run (Xamarin.Android.Binder.CodeGeneratorOptions) at Xamarin.Android.Binder.CodeGenerator.Main (string[]) at (wrapper runtime-invoke) <Module>.runtime_invoke_int_object (object,intptr,intptr,intptr) Add a check for this scenario to `generator` to prevent the `StackOverflowException` and instead remove the offending type. This removal will be logged with other type removals in the `java-resolution-report.log` (f658ab2): The class '[Class] my.namespace.c5' was removed because the base type 'my.namespace.c5' is invalid.
1 parent 2c8b0a8 commit 58de60f

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

src/Java.Interop.Tools.JavaTypeSystem/JavaModels/JavaClassModel.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public override void Resolve (JavaTypeCollection types, ICollection<JavaUnresolv
3737
throw;
3838
}
3939

40+
// Apparently some Java obfuscator sets a class's base type to itself, which
41+
// results in a stack overflow. Check for this case and remove the offending type.
42+
if (BaseTypeReference.ReferencedType is JavaClassModel jcm && jcm == this) {
43+
unresolvables.Add (new JavaUnresolvableModel (this, BaseTypeGeneric, UnresolvableType.InvalidBaseType));
44+
throw new JavaTypeResolutionException (BaseTypeGeneric);
45+
}
46+
4047
// We don't resolve reference-only types by default, so if our base class
4148
// is a reference only type, we need to force it to resolve here. This will be
4249
// needed later when we attempt to resolve base methods.

src/Java.Interop.Tools.JavaTypeSystem/Utilities/JavaUnresolvableModel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public string GetDisplayMessage ()
2525
$"The type '{member?.DeclaringType.FullName}' was removed because the required {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign." :
2626
$"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because its name contains a dollar sign.";
2727

28+
if (Type == UnresolvableType.InvalidBaseType)
29+
return $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the base type '{MissingType}' is invalid.";
30+
2831
if (Unresolvable is JavaTypeModel)
2932
return $"The {GetUnresolvableType ()} '{GetUnresolvable ()}' was removed because the Java {GetReason ()} '{MissingType}' could not be found.";
3033

@@ -77,6 +80,7 @@ public enum UnresolvableType
7780
ReturnType,
7881
ParameterType,
7982
BaseType,
80-
ImplementsType
83+
ImplementsType,
84+
InvalidBaseType,
8185
}
8286
}

tests/Java.Interop.Tools.JavaTypeSystem-Tests/JavaTypeCollectionTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,30 @@ public void InheritedGenericTypeParameters ()
122122
Assert.IsNotNull (t.Methods.SingleOrDefault (m => m.Name == "DoT"), "Method with generic T not found");
123123
Assert.IsNotNull (t.Methods.SingleOrDefault (m => m.Name == "DoU"), "Method with generic U not found");
124124
}
125+
126+
[Test]
127+
public void InvalidBaseTypeResolution ()
128+
{
129+
var api = new JavaTypeCollection ();
130+
131+
// Create "my.ns" package
132+
var my_ns = api.AddPackage ("my.ns", "my/ns");
133+
134+
// Create new "my.ns.MyObject" type with "my.ns.MyObject" as base type
135+
var jlo = JavaApiTestHelper.CreateClass (my_ns, "MyObject", javaBaseType: "my.ns.MyObject", javaBaseTypeGeneric: "my.ns.MyObject");
136+
137+
api.AddType (jlo);
138+
139+
// Run the resolver
140+
var results = api.ResolveCollection ();
141+
142+
// Ensure we marked it as unresolvable
143+
Assert.AreEqual (1, results.Count);
144+
Assert.AreEqual (1, results [0].Unresolvables.Count);
145+
Assert.AreEqual ("The class '[Class] my.ns.MyObject' was removed because the base type 'my.ns.MyObject' is invalid.", results [0].Unresolvables [0].GetDisplayMessage ());
146+
147+
// Ensure we removed the type from the collection
148+
Assert.AreEqual (0, api.TypesFlattened.Count);
149+
}
125150
}
126151
}

0 commit comments

Comments
 (0)