[External] : Re: Help with VM Crash using the foreign linker

Jorn Vernee jorn.vernee at oracle.com
Mon May 17 12:23:03 UTC 2021

On 16/05/2021 02:27, Duncan McLean wrote:
> Hi Jorn,
> Thank you for the suggestion. I've looked into this and the 
> FunctionDescriptor is exactly as you have suggested: 
>  FunctionDescriptor.of(C_DOUBLE, C_POINTER).
Sorry, I think I've misread the stack trace earlier. I initially was 
surprised to see invokeMoves in the stack trace for an intrinsified 
case, but we also use that as a fallback before the JIT compiler kicks in.
> I went so far as to hard code FunctionDescriptor call when I was 
> running my TestUsingStructs test case. The FunctionDescriptor is build at:
> https://github.com/boulder-on/JPassport/blob/ddaf4482045b83be95000e7fcc240bf720f0b525/jpassport/src/main/java/jpassport/PassportFactory.java#L89 
> <https://urldefense.com/v3/__https://github.com/boulder-on/JPassport/blob/ddaf4482045b83be95000e7fcc240bf720f0b525/jpassport/src/main/java/jpassport/PassportFactory.java*L89__;Iw!!GqivPVa7Brio!JBI3NcMrZhS0vy2j4WYCWeB6uPuulrfmMpdF2nnY0pOBQ8viDh7nsMiHug6gvoSQ$>
> For some reason I can only run my test cases from my IDE, maven 
> doesn't like something I'm doing (right now it finds my test classes, 
> but no test cases). However, when run from the IDE, 
> TestUsingStructs crashes the vm every time on the first invokeExact 
> call it encounters. When I comment out the deleting of previously 
> compiled files and the compiling of new files (such that the test runs 
> with the last compiled version) the test case always works.
> Line for deleting previous compiles:
> https://github.com/boulder-on/JPassport/blob/ddaf4482045b83be95000e7fcc240bf720f0b525/jpassport/src/main/java/jpassport/PassportWriter.java#L535 
> <https://urldefense.com/v3/__https://github.com/boulder-on/JPassport/blob/ddaf4482045b83be95000e7fcc240bf720f0b525/jpassport/src/main/java/jpassport/PassportWriter.java*L535__;Iw!!GqivPVa7Brio!JBI3NcMrZhS0vy2j4WYCWeB6uPuulrfmMpdF2nnY0pOBQ8viDh7nsMiHuhddCXPS$>
> Line for compiling new classes:
> https://github.com/boulder-on/JPassport/blob/ddaf4482045b83be95000e7fcc240bf720f0b525/jpassport/src/main/java/jpassport/PassportWriter.java#L551 
> <https://urldefense.com/v3/__https://github.com/boulder-on/JPassport/blob/ddaf4482045b83be95000e7fcc240bf720f0b525/jpassport/src/main/java/jpassport/PassportWriter.java*L551__;Iw!!GqivPVa7Brio!JBI3NcMrZhS0vy2j4WYCWeB6uPuulrfmMpdF2nnY0pOBQ8viDh7nsMiHuhdBauR8$>
> Is there any more detailed logging I can generate?

You could try running with 

Looking at the crash closer, I see the EXCEPTION_ACCESS_VIOLATION you're 
getting is due to a data execution prevention. I've been able to 
reproduce the crash here, and running with the above logging option, it 
seems that the address being passed into the native call is incorrect:

Buffer state before:
Next PC: 7ffaea2e10dc

And then in the crash log:

siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), data execution 
prevention violation at address 0x00007ffaea2e10dc

Stepping further back in the execution, it seems that this address is 
being loaded straight from the library, I see the 10dc as a virtual 
address for that function in dumpbin:

     ordinal hint RVA      name

           7    6 000010DC passStructWithArrays = 

So, it seems to be a problem with the library.

After some trial and error, it seems that the library is being unloaded 
during the test execution (try setting a breakpoint in 
LibrariesHelper::tryUnload), which would invalidate the function 
address. Note that the LibraryLookup object needs to be kept strongly 
reachable in order to keep the library loaded, in the version of the 
code you're using (we've changed this recently to be more robust). This 
is normally done by the method handle automatically, because it keeps a 
strong reference to the Symbol you use when linking, which then keeps 
the library alive [1].

However, in PassportFactory, you are discarding the Symbol, and only 
keeping the address:

MethodHandle methodHandle =linker.
         downcallHandle(symb.address(),  <---------------

Which means the library will not be kept loaded by the MethodHandle, and 
indeed it is being unloaded.

Symbol implements Addressable already, so there is no need to call 
.address() here. If I remove that call, the crash goes away, and the 
test passes.


[1] : 

> Thanks again,
> Duncan
> On Sat, May 15, 2021 at 9:36 AM Jorn Vernee <jorn.vernee at oracle.com 
> <mailto:jorn.vernee at oracle.com>> wrote:
>     Hi,
>     Looking at the crash log, as well as the test, you seem to be
>     passing a
>     single struct to a native function, but the stack trace in the
>     error log
>     shows that the call is not being intrinsified, which should not be
>     the
>     case if you're only passing a single struct on Windows. Either it
>     fits
>     in a register, or it's passed by reference, both of which cases are
>     intrinsified.
>     The most likely explanation for that seems to be that you are not
>     using
>     the right FunctionDescriptor when linking, and a crash occurs when
>     the
>     native code is trying to access what it thinks is a pointer to a
>     struct.
>     This is undefined behavior territory, which could explain why the
>     crash
>     only occurs in certain scenarios.
>     My advice would be to check the FunctionDescriptor you're using
>     for the
>     linkage request, and make sure it matches the native function
>     declaration. Looking at [1], the FunctionDescriptor you need is
>     FunctionDescriptor.of(C_DOUBLE, C_POINTER).
>     HTH,
>     Jorn
>     [1] :
>     https://github.com/boulder-on/JPassport/blob/52bfa8b4390fdde57582722a1c8098958088de08/fl_dll/library.c#L330
>     <https://urldefense.com/v3/__https://github.com/boulder-on/JPassport/blob/52bfa8b4390fdde57582722a1c8098958088de08/fl_dll/library.c*L330__;Iw!!GqivPVa7Brio!JBI3NcMrZhS0vy2j4WYCWeB6uPuulrfmMpdF2nnY0pOBQ8viDh7nsMiHumoug0fD$>

More information about the panama-dev mailing list