Skip to content

Commit

Permalink
Fix invalid return value when calling injected methods via Il2Cpp ref…
Browse files Browse the repository at this point in the history
…lection (#74)
  • Loading branch information
limoka authored Feb 14, 2023
1 parent 44f18f0 commit e28b791
Showing 1 changed file with 76 additions and 23 deletions.
99 changes: 76 additions & 23 deletions Il2CppInterop.Runtime/Injection/ClassInjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static unsafe partial class ClassInjector
private static readonly Dictionary<IntPtr, (MethodInfo, Dictionary<IntPtr, IntPtr>)>
InflatedMethodFromContextDictionary = new();

private static readonly ConcurrentDictionary<string, InvokerDelegate> InvokerCache = new();
private static readonly ConcurrentDictionary<string, Delegate> InvokerCache = new();

private static readonly ConcurrentDictionary<(Type type, FieldAttributes attrs), IntPtr>
_injectedFieldTypes = new();
Expand Down Expand Up @@ -577,7 +577,16 @@ private static bool IsMethodEligible(MethodInfo method)
converted.Name = Marshal.StringToHGlobalAnsi(methodName);
converted.Class = declaringClass.ClassPointer;

var invoker = new InvokerDelegate(StaticVoidIntPtrInvoker);
Delegate invoker;
if (UnityVersionHandler.IsMetadataV29OrHigher)
{
invoker = new InvokerDelegateMetadataV29(StaticVoidIntPtrInvoker_MetadataV29);
}
else
{
invoker = new InvokerDelegate(StaticVoidIntPtrInvoker);
}

GCHandle.Alloc(invoker);
converted.InvokerMethod = Marshal.GetFunctionPointerForDelegate(invoker);

Expand Down Expand Up @@ -767,24 +776,36 @@ public static void Finalize(IntPtr ptr)
GCHandle.FromIntPtr(gcHandle).Free();
}

private static InvokerDelegate GetOrCreateInvoker(MethodInfo monoMethod)
private static Delegate GetOrCreateInvoker(MethodInfo monoMethod)
{
return InvokerCache.GetOrAdd(ExtractSignature(monoMethod),
(_, monoMethodInner) => CreateInvoker(monoMethodInner), monoMethod);
static (_, monoMethodInner) => CreateInvoker(monoMethodInner), monoMethod);
}

private static Delegate GetOrCreateTrampoline(MethodInfo monoMethod)
{
return CreateTrampoline(monoMethod);
}

private static InvokerDelegate CreateInvoker(MethodInfo monoMethod)
private static Delegate CreateInvoker(MethodInfo monoMethod)
{
var parameterTypes = new[] { typeof(IntPtr), typeof(Il2CppMethodInfo*), typeof(IntPtr), typeof(IntPtr*) };
DynamicMethod method;
if (UnityVersionHandler.IsMetadataV29OrHigher)
{
var parameterTypes = new[] { typeof(IntPtr), typeof(Il2CppMethodInfo*), typeof(IntPtr), typeof(IntPtr*), typeof(IntPtr*) };

method = new DynamicMethod("Invoker_" + ExtractSignature(monoMethod),
MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(void),
parameterTypes, monoMethod.DeclaringType, true);
}
else
{
var parameterTypes = new[] { typeof(IntPtr), typeof(Il2CppMethodInfo*), typeof(IntPtr), typeof(IntPtr*) };

var method = new DynamicMethod("Invoker_" + ExtractSignature(monoMethod),
MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(IntPtr),
parameterTypes, monoMethod.DeclaringType, true);
method = new DynamicMethod("Invoker_" + ExtractSignature(monoMethod),
MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(IntPtr),
parameterTypes, monoMethod.DeclaringType, true);
}

var body = method.GetILGenerator();

Expand All @@ -806,38 +827,68 @@ private static InvokerDelegate CreateInvoker(MethodInfo monoMethod)
new[] { typeof(IntPtr) }.Concat(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType()))
.ToArray());

if (monoMethod.ReturnType == typeof(void))
if (UnityVersionHandler.IsMetadataV29OrHigher)
{
body.Emit(OpCodes.Ldc_I4_0);
body.Emit(OpCodes.Conv_I);
if (monoMethod.ReturnType != typeof(void))
{
var returnValue = body.DeclareLocal(monoMethod.ReturnType.NativeType());
body.Emit(OpCodes.Stloc, returnValue);
body.Emit(OpCodes.Ldarg_S, (byte)4);
body.Emit(OpCodes.Ldloc, returnValue);
body.Emit(OpCodes.Stobj, returnValue.LocalType);
}
}
else if (monoMethod.ReturnType.IsValueType)
else
{
var returnValue = body.DeclareLocal(monoMethod.ReturnType);
body.Emit(OpCodes.Stloc, returnValue);
var classField = typeof(Il2CppClassPointerStore<>).MakeGenericType(monoMethod.ReturnType)
.GetField(nameof(Il2CppClassPointerStore<int>.NativeClassPtr));
body.Emit(OpCodes.Ldsfld, classField);
body.Emit(OpCodes.Ldloca, returnValue);
body.Emit(OpCodes.Call, typeof(IL2CPP).GetMethod(nameof(IL2CPP.il2cpp_value_box))!);
if (monoMethod.ReturnType == typeof(void))
{
body.Emit(OpCodes.Ldc_I4_0);
body.Emit(OpCodes.Conv_I);
}
else if (monoMethod.ReturnType.IsValueType)
{
var returnValue = body.DeclareLocal(monoMethod.ReturnType);
body.Emit(OpCodes.Stloc, returnValue);
var classField = typeof(Il2CppClassPointerStore<>).MakeGenericType(monoMethod.ReturnType)
.GetField(nameof(Il2CppClassPointerStore<int>.NativeClassPtr));
body.Emit(OpCodes.Ldsfld, classField);
body.Emit(OpCodes.Ldloca, returnValue);
body.Emit(OpCodes.Call, typeof(IL2CPP).GetMethod(nameof(IL2CPP.il2cpp_value_box))!);
}
}

body.Emit(OpCodes.Ret);

GCHandle.Alloc(method);

var @delegate = (InvokerDelegate)method.CreateDelegate(typeof(InvokerDelegate));
var @delegate = method.CreateDelegate(GetInvokerDelegateType());
GCHandle.Alloc(@delegate);
return @delegate;
}

private static Type GetInvokerDelegateType()
{
if (UnityVersionHandler.IsMetadataV29OrHigher)
{
return typeof(InvokerDelegateMetadataV29);
}

return typeof(InvokerDelegate);
}

private static IntPtr StaticVoidIntPtrInvoker(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj,
IntPtr* args)
{
Marshal.GetDelegateForFunctionPointer<VoidCtorDelegate>(methodPointer)(obj);
return IntPtr.Zero;
}

private static void StaticVoidIntPtrInvoker_MetadataV29(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj,
IntPtr* args, IntPtr* returnValue)
{
Marshal.GetDelegateForFunctionPointer<VoidCtorDelegate>(methodPointer)(obj);
}

private static Delegate CreateTrampoline(MethodInfo monoMethod)
{
var nativeParameterTypes = new[] { typeof(IntPtr) }.Concat(monoMethod.GetParameters()
Expand Down Expand Up @@ -1093,8 +1144,10 @@ private static Type SystemTypeFromIl2CppType(Il2CppTypeStruct* typePointer)
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr InvokerDelegate(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj,
IntPtr* args);
private delegate void InvokerDelegateMetadataV29(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj, IntPtr* args, IntPtr* returnValue);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr InvokerDelegate(IntPtr methodPointer, Il2CppMethodInfo* methodInfo, IntPtr obj, IntPtr* args);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void VoidCtorDelegate(IntPtr objectPointer);
Expand Down

0 comments on commit e28b791

Please sign in to comment.