diff --git a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs
index 3652065..528e88d 100644
--- a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs
+++ b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs
@@ -228,6 +228,14 @@ namespace Il2CppInspector.Cpp
ns.ReserveName("_");
fieldType = types.Struct(name + "__Fields");
var baseFieldType = types[TypeNamer.GetName(ti.BaseType) + "__Fields"];
+
+ if (baseFieldType == null)
+ {
+ // if we end up here, there is a loop in the type generation.
+ // this is not currently supported, so we throw an exception.
+ throw new InvalidOperationException($"Failed to generate type for {ti}");
+ }
+
fieldType.AddField("_", baseFieldType);
GenerateFieldList(fieldType, ns, ti);
}
@@ -437,16 +445,30 @@ namespace Il2CppInspector.Cpp
/// A string containing C type declarations
public List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType,
CppComplexType vtableType, CppComplexType staticsType)> GenerateRemainingTypeDeclarations() {
- var decl = GenerateVisitedFieldStructs().Select(s =>
- (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType) null, (CppComplexType) null)).ToList();
+ try
+ {
+ var decl = GenerateVisitedFieldStructs().Select(s =>
+ (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType)null,
+ (CppComplexType)null))
+ .ToList();
- foreach (var ti in TodoTypeStructs) {
- var (cls, statics, vtable) = GenerateTypeStruct(ti);
- decl.Add((ti, null, cls, null, vtable, statics));
+ foreach (var ti in TodoTypeStructs)
+ {
+ var (cls, statics, vtable) = GenerateTypeStruct(ti);
+ decl.Add((ti, null, cls, null, vtable, statics));
+ }
+
+ return decl;
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ finally
+ {
+ TodoTypeStructs.Clear();
+ TodoFieldStructs.Clear();
}
- TodoTypeStructs.Clear();
-
- return decl;
}
#endregion
diff --git a/Il2CppInspector.Common/Cpp/CppField.cs b/Il2CppInspector.Common/Cpp/CppField.cs
index 2ac419f..631e762 100644
--- a/Il2CppInspector.Common/Cpp/CppField.cs
+++ b/Il2CppInspector.Common/Cpp/CppField.cs
@@ -4,8 +4,6 @@
All rights reserved.
*/
-using System;
-
namespace Il2CppInspector.Cpp
{
// A field in a C++ type
diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs
index 64b087f..42503c9 100644
--- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs
+++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs
@@ -337,7 +337,15 @@ namespace Il2CppInspector
}
// Read method invoker pointer indices - one per method
- MethodInvokerIndices.Add(module, Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int) module.MethodPointerCount));
+ try
+ {
+ MethodInvokerIndices.Add(module,
+ Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int)module.MethodPointerCount));
+ }
+ catch (InvalidOperationException)
+ {
+ MethodInvokerIndices.Add(module, [..new int[(int)module.MethodPointerCount]]);
+ }
}
}
@@ -398,12 +406,21 @@ namespace Il2CppInspector
var type = TypeReferences[i];
if (type.Type.IsTypeDefinitionEnum())
{
- type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize;
+ if (type.Data.Type.PointerValue >= baseDefinitionPtr)
+ type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize;
+
+ Debug.Assert(Metadata!.Types.Length > type.Data.KlassIndex);
}
else if (type.Type.IsGenericParameterEnum())
{
- type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize;
+ if (type.Data.Type.PointerValue >= baseGenericPtr)
+ type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize;
+
+ Debug.Assert(Metadata!.GenericParameters.Length > type.Data.KlassIndex);
}
+
+ Debug.Assert((long)type.Data.Value >= 0);
+
builder.Add(type);
}
TypeReferences = builder.MoveToImmutable();
diff --git a/Il2CppInspector.Common/Model/AppModel.cs b/Il2CppInspector.Common/Model/AppModel.cs
index 923e6ee..59822fc 100644
--- a/Il2CppInspector.Common/Model/AppModel.cs
+++ b/Il2CppInspector.Common/Model/AppModel.cs
@@ -236,7 +236,17 @@ namespace Il2CppInspector.Model
break;
case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef:
var method = TypeModel.GetMetadataUsageMethod(usage);
+
declarationGenerator.IncludeMethod(method);
+ var definitions = declarationGenerator.GenerateRemainingTypeDeclarations();
+ if (definitions == null)
+ {
+ // if we end up here, type generation has failed
+ // todo: this try/catch is a massive hack to sidestep the original issue of generation failing,
+ // todo: this needs to be improved.
+ break;
+ }
+
AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
// Any method here SHOULD already be in the Methods list
@@ -247,6 +257,7 @@ namespace Il2CppInspector.Model
Methods.Add(method, fnPtr, new AppMethod(method, fnPtr) { Group = Group });
}
Methods[method].MethodInfoPtrAddress = address;
+
break;
// FieldInfo is used for array initializers.
diff --git a/Il2CppInspector.Common/Outputs/AssemblyShims.cs b/Il2CppInspector.Common/Outputs/AssemblyShims.cs
index c111691..3446761 100644
--- a/Il2CppInspector.Common/Outputs/AssemblyShims.cs
+++ b/Il2CppInspector.Common/Outputs/AssemblyShims.cs
@@ -430,7 +430,7 @@ namespace Il2CppInspector.Outputs
if (method.VirtualAddress.HasValue) {
var args = new List<(string,object)> {
("RVA", (method.VirtualAddress.Value.Start - model.Package.BinaryImage.ImageBase).ToAddressString()),
- ("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start))),
+ ("Offset", $"0x{model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start):X}"),
("VA", method.VirtualAddress.Value.Start.ToAddressString())
};
if (method.Definition.Slot != ushort.MaxValue)
@@ -470,7 +470,7 @@ namespace Il2CppInspector.Outputs
return def.AddAttribute(module, attributeAttribute,
("Name", ca.AttributeType.Name),
("RVA", (ca.VirtualAddress.Start - model.Package.BinaryImage.ImageBase).ToAddressString()),
- ("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(ca.VirtualAddress.Start)))
+ ("Offset", $"0x{model.Package.BinaryImage.MapVATR(ca.VirtualAddress.Start):X}")
);
}
diff --git a/Il2CppInspector.Common/Reflection/TypeModel.cs b/Il2CppInspector.Common/Reflection/TypeModel.cs
index 2cdfd7f..1dbb8b0 100644
--- a/Il2CppInspector.Common/Reflection/TypeModel.cs
+++ b/Il2CppInspector.Common/Reflection/TypeModel.cs
@@ -165,10 +165,9 @@ namespace Il2CppInspector.Reflection
// Generic type definitions have an invoker index of -1
foreach (var method in MethodsByDefinitionIndex) {
var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition);
- if (index != -1) {
- if (MethodInvokers[index] == null)
- MethodInvokers[index] = new MethodInvoker(method, index);
-
+ if (index != -1)
+ {
+ MethodInvokers[index] ??= new MethodInvoker(method, index);
method.Invoker = MethodInvokers[index];
}
}
@@ -176,10 +175,11 @@ namespace Il2CppInspector.Reflection
// Create method invokers sourced from generic method invoker indices
foreach (var spec in GenericMethods.Keys) {
if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) {
- if (MethodInvokers[index] == null)
- MethodInvokers[index] = new MethodInvoker(GenericMethods[spec], index);
-
- GenericMethods[spec].Invoker = MethodInvokers[index];
+ if (index != -1)
+ {
+ MethodInvokers[index] ??= new MethodInvoker(GenericMethods[spec], index);
+ GenericMethods[spec].Invoker = MethodInvokers[index];
+ }
}
}