BepInEx / Il2CppInterop

A tool interoperate between CoreCLR and Il2Cpp at runtime
GNU Lesser General Public License v3.0
206 stars 66 forks source link

Method not found: 'Void System.__Canon..ctor(IntPtr) #73

Closed dommrogers closed 1 year ago

dommrogers commented 1 year ago

MelonLoader v0.6.0 ALPHA Pre-Release Game Name: TheLongDark Unity Version: 2021.3.6f1 Game Version: 2.06 Using Il2CppInterop Version = 1.4.3-ci.244

The following exception occurs when trying to either

string text = "";
Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject<string>("some test text here", out text);
-----------------------------------------------
string text = "";
SaveGameSlots.TryLoadDataFromSlot<string>(SaveSlotName,"KeyToGet", out text);
System.MissingMethodException: Method not found: 'Void System.__Canon..ctor(IntPtr)'.
   at Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject[T](String text, T& result)

It was suggested to me that it's a potential problem with new T(intPtr2) in

[CallerCount(6)]
        [CachedScanResults(RefRangeStart = 1397578, RefRangeEnd = 1397584, XrefRangeStart = 1397567, XrefRangeEnd = 1397578, MetadataInitTokenRva = 0L, MetadataInitFlagRva = 0L)]
        public unsafe static bool TryDeserializeObject<T>(string text, out T result)
        {
            System.IntPtr* ptr = stackalloc System.IntPtr[2];
            *ptr = IL2CPP.ManagedStringToIl2Cpp(text);
            byte* num = (byte*)ptr + checked((nuint)1u * unchecked((nuint)sizeof(System.IntPtr)));
            System.IntPtr intPtr = IL2CPP.Il2CppObjectBaseToPtr(System.Runtime.CompilerServices.Unsafe.As<T, Il2CppObjectBase>(ref result));
            *(System.IntPtr**)num = &intPtr;
            System.IntPtr exc;
            System.IntPtr obj = IL2CPP.il2cpp_runtime_invoke(MethodInfoStoreGeneric_TryDeserializeObject_Public_Static_Boolean_String_byref_T_0<T>.Pointer, (System.IntPtr)0, (void**)ptr, ref exc);
            Il2CppException.RaiseExceptionIfNecessary(exc);
            System.IntPtr intPtr2 = intPtr;
            System.Runtime.CompilerServices.Unsafe.As<T, object>(ref result) = ((intPtr2 == (System.IntPtr)0) ? ((T)null) : new T(intPtr2));
            return *(bool*)IL2CPP.il2cpp_object_unbox(obj);
        }

"System.__Canon is an implementation detail related to the way generics are implemented in the CLR" https://stackoverflow.com/questions/16854393/strange-system-canon-exception

Please let me know if i can provide any other information or test anything, Dom (STBlade)

Kasuromi commented 1 year ago

Could you try passing Il2CppSystem.String as a generic parameter and let me know what kind of result you get.

dommrogers commented 1 year ago

That was also tried and gave me the same result.

Sorry, forgot to mention that

On Sun, 5 Feb 2023, 22:10 Kasuromi, @.***> wrote:

Could you try passing Il2CppSystem.String as a generic parameter and let me know what kind of result you get.

— Reply to this email directly, view it on GitHub https://github.com/BepInEx/Il2CppInterop/issues/73#issuecomment-1418278503, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFMVXZ46IRNOXOCUZZZ2CLWWAQOBANCNFSM6AAAAAAUSAEECU . You are receiving this because you authored the thread.Message ID: @.***>

dommrogers commented 1 year ago

Just to confirm now that I am back at the computer.

Il2CppSystem.String text = "";
Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject<Il2CppSystem.String>("some test text here", out text);
During invoking native->managed trampoline
System.MissingMethodException: Method not found: 'Void System.__Canon..ctor(IntPtr)'.
at Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject[T](String text, T& result)

and for good measure

Il2CppSystem.String test_string = "some test text here";
Il2CppSystem.String text = "";
Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject<Il2CppSystem.String>(test_string, out text);
During invoking native->managed trampoline
System.MissingMethodException: Method not found: 'Void System.__Canon..ctor(IntPtr)'.
at Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject[T](String text, T& result)
dommrogers commented 1 year ago

Not sure if this helps at all but found another one.

Panel_Log panel_log = InterfaceManager.GetPanel<Panel_Log>();
panel_log.m_RockCacheListByRegion.TryGetValue(sceneName, out rockCacheInfoList)
Exception in IL2CPP-to-Managed trampoline, not passing it to il2cpp: System.MissingMethodException: Method not found: 'Void System.__Canon..ctor(IntPtr)'.
   at Il2CppSystem.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
Kasuromi commented 1 year ago

Since I don't own the game I was only able to reproduce this issue with Dictionary.TryGetValue.

I've gone ahead and made some changes to how we handle writing data to generic byref types, you can check out the build artifacts from the generic-byrefs branch.

I only tested dictionaries with value types of int, string & long, so please let me know if you run into any other issues.

dommrogers commented 1 year ago

I'm not quite sure how to go about replacing Il2Cppinterop with MelonLoader 0.6.0 but as soon as I figure it out and give it a test it I'll let you know.

Cheers.

dommrogers commented 1 year ago

So far the changes have fixed the error 'Void System.__Canon..ctor(IntPtr)' but I am still getting exceptions

I am still testing the "SaveGameSlots.TryLoadDataFromSlot" method as it is no longer throwing an exception but also giving me no return data.. Will update when I know more about that one.

string test_string = "some test text here";
string text = "";
Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject<string>(test_string, out text);
Il2CppInterop.Runtime.ObjectCollectedException: Object was garbage collected in IL2CPP domain
   at Il2CppInterop.Runtime.InteropTypes.Il2CppObjectBase.get_Pointer() in /home/runner/work/Il2CppInterop/Il2CppInterop/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs:line 31
   at Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject[T](String text, T& result)

and

Il2CppSystem.String test_string1 = "some test text here";
Il2CppSystem.String text1 = "";
Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject<Il2CppSystem.String>(test_string1, out text1);
System.TypeInitializationException: The type initializer for 'MethodInfoStoreGeneric_TryDeserializeObject_Public_Static_Boolean_String_byref_T_0`1' threw an exception.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   --- End of inner exception stack trace ---
   at Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject[T](String text, T& result)

and for completeness

string test_string2 = "some test text here";
Il2CppSystem.String text2 = "";
Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject<Il2CppSystem.String>(test_string2, out text2);
System.TypeInitializationException: The type initializer for 'MethodInfoStoreGeneric_TryDeserializeObject_Public_Static_Boolean_String_byref_T_0`1' threw an exception.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   --- End of inner exception stack trace ---
   at Il2CppTLD.Serialization.SerializationUtils.TryDeserializeObject[T](String text, T& result)

Thanks

Kasuromi commented 1 year ago

It appears I didn't catch output parameters needing to be zero-initialized. This issue should be resolved in the latest commit.

dommrogers commented 1 year ago

So far the changes appear to be working as expected with one exception.

Using Il2CppSystem.String I get the following

During invoking native->managed trampoline
System.TypeInitializationException: The type initializer for 'MethodInfoStoreGeneric_TryLoadDataFromSlot_Public_Static_Boolean_String_String_byref_T_0`1' threw an exception.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   --- End of inner exception stack trace ---
   at Il2Cpp.SaveGameSlots.TryLoadDataFromSlot[T](String slotname, String filename, T& data)

I don't think I need to use this but thought it was worth mentioning incase it indicates a bigger issue.

FYI - Using string doesn't throw any exception.

Kasuromi commented 1 year ago

You should use the managed string type instead of Il2CppSystem.String.

Il2CppInterop only considers the managed string type when invoking methods at runtime and the only exception to this is field injection I believe.

dommrogers commented 1 year ago

No problem, so far no issues then.

Just need to figure out how to work around the methods I want now enforcing certain objects and no longer supporting just strings.

Thanks for this.

dommrogers commented 1 year ago

Just came across an issue the new DLL's caused.

System.MissingMethodException: Method not found: 'Void UnityEngine.RaycastHit..ctor(IntPtr)'.

Restoring the versions that come with MelonLoader fixed this.

Let me know what else I can provide to help hunt this down.

Kasuromi commented 1 year ago

That should be fixed by the latest artifacts from #79, try those if you haven't already

dommrogers commented 1 year ago

Yep confirmed, latest artifacts work fine.

Thanks :)