ikvmnet / ikvm

A Java Virtual Machine and Bytecode-to-IL Converter for .NET
Other
1.17k stars 110 forks source link

Access violation exception somewhere near GetMethodArgs #420

Closed wasabii closed 10 months ago

wasabii commented 10 months ago

https://github.com/ikvmnet/ikvm/blob/2d053c4a427f5ca96466e09c7c7e48297e681bb5/src/libjvm/jni_vargs.c#L17

@AaronRobinsonMSFT I don't suppose you can provide some assistance on this one, eh? You seem to know what you're doing.

I'm getting a periodic access violation exception here. It's not consistent. It doesn't happen inside the VS debugger. It only happens, as far as I can tell, when running dotnet test from the command line, through this code. And it only happens once out of every 4 or 5 times. And... I think it's only happening on Framework on Windows.

So, I've resulted to catching a dump file and using WinDbg.

STACK_TEXT:  
0000003a`d04bd8c8 00007ffa`573ebb58     : 00007ffa`575ccca8 00007ffa`575ccc98 00007ffa`575ccc88 00007ffa`575ccc98 : clr!GCHandleManager::GetHandleContext+0x7
0000003a`d04bd8d0 00007ffa`4402db6b     : 0000003a`d04bebd0 00000187`01d96a80 0000003a`d04bda70 00000187`00861ef0 : clr!MarshalNative::GCHandleInternalCheckDomain+0x48
0000003a`d04bd900 00007ff9`f88f3f31     : 00000000`80000000 00007ff9`f862e8f8 00000000`00000000 00000000`00000000 : mscorlib_ni!System.Runtime.InteropServices.GCHandle.FromIntPtr+0x3b
0000003a`d04bd940 00007ff9`f9712016     : 00000187`651e70a0 0000003a`d04bdbc0 0000003a`d04bda80 00000187`01d96a80 : 0x00007ff9`f88f3f31
0000003a`d04bd9a0 00007ff9`f9711e9f     : 00000187`651e70a0 00000187`651e70a0 0000003a`d04bdbc0 0000003a`d04bdbc0 : 0x00007ff9`f9712016
0000003a`d04bd9e0 00007ff9`f84aa2b8     : 00000187`00861ef0 00000187`651e70a0 0000003a`d04bdbc0 0000003a`d04bdbc0 : 0x00007ff9`f9711e9f
0000003a`d04bda90 00007ffa`5700fc9e     : 00000000`80000000 00090f04`0001005f 00000187`00861ef0 00007ff9`f84ade77 : 0x00007ff9`f84aa2b8
0000003a`d04bdaf0 00007ff9`7c6c719a     : 00000000`00000000 00000187`68003030 00000001`00000000 00000001`00000000 : clr!UMThunkStub+0x6e
0000003a`d04bdb80 00007ff9`7c6c7132     : 00000000`00000028 00000000`00000000 00000000`00000000 0000004f`544f594b : jvm!_JNI_NewObjectV+0x4a
0000003a`d04bdd00 00007ff9`58641d55     : 00000187`00861ef0 00000000`00000401 00000000`00000000 00000000`00000401 : jvm!_JNI_NewObject+0x42
0000003a`d04bdd50 00007ff9`55214123     : 00000000`00000005 00007ff9`f849e500 00000187`01d96a80 00000187`01d96a80 : iava!JNU_NewStringPlatform+0x245

It looks like it's the call to __JNI_NewObjectV, happening as a result of the the __JNI_NewObject call. The macro in jni_varargs.h calls back into .NET. The point of GetMethodArgs is to take a method handle, and return the count of arguments and their types (as a signature). So the C code can unpack the va_List into an array.

I don't see it enter into GetMethodArgs. So, it's not getting into user code.

I thought it might be related to calling conventions again. Or the delegate getting GC'd. The delegate is in JNINativeInterface.cs:

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate int GetMethodArgsDelegateType(JNIEnv* pEnv, jmethodID methodID, byte* sig);

It's forced to cdecl.

We store this delegate away on the reserved0 field of JNINativeInterface, since it's IKVM-only. We also store the delegate instance itself on a static readonly field. It should not be getting GC'd.

We call it from C:

typedef int (__cdecl *GetMethodArgs_t)(JNIEnv* pEnv, jmethodID method, char* sig);
#define GET_METHOD_ARGS(pEnv, method, sig) (((GetMethodArgs_t)((*pEnv)->reserved0))(pEnv, methodID, sig))
    char sig[257];\
    int argc = GET_METHOD_ARGS(pEnv, methodID, sig);\

I set this specifically to cdecl.

I've been working with this for a couple days now, and just can't figure out the issue.

wasabii commented 10 months ago

Nevermind. I'm an idiot.

AppDomains. That has to be it.