ikvmnet / ikvm

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

JNI Fails to load library methods #372

Closed TheLastRar closed 1 year ago

TheLastRar commented 1 year ago

IKVM version : image-netcoreapp3.1-win7-x64 commit https://github.com/ikvmnet/ikvm/commit/37e3bf38828adfa4faa3e72fb0cd7a3f65fb5b12 taken from actions build

This is a regression as a result of the unpack branch getting merged

Take the example code from https://github.com/ikvmnet/ikvm/issues/344, The C code was compiled using the default settings Visual Studio 2022 creates using the library project template. Only change to project settings was to disable and remove pre-compiled headers.

IKVM was used as a JVM, directory of native library was specified using the -Djava.library.path= argument.

OpenJDK produces the following output

Call Java with 3987654321
Got 3987654321

IKVM instead produces this output

Exception in thread "Thread-0" java.lang.UnsatisfiedLinkError: jnitest/Main.setCallback(Ljava/lang/reflect/Method;)V
        at IKVM.Runtime.JNI.JNIFrame.GetFuncPtr(JNIFrame.cs:138)
        at jnitest.Main.setCallback(Main.java)
        at jnitest.Main.main(Main.java:19)
        at java.lang.reflect.Method.invoke(Method.java:486)
        at IKVM.Runtime.Accessors.Java.Lang.Reflect.MethodAccessor.InvokeInvoke(MethodAccessor.cs:35)
TheLastRar commented 1 year ago

LWJGL2 runs into a similar issue with its native libraries

wasabii commented 1 year ago

Boo. Somehow this escaped tests. Have a handleful of automated JNI tests.... but I don't think I have any that use java.exe directly, except what comes with OpenJDK.

wasabii commented 1 year ago

Can you try this with an absolute path in System.loadLibrary? Want to confirm whether it's in the 'find the library' or 'find the function' side of things.

TheLastRar commented 1 year ago

Can you try this with an absolute path in System.loadLibrary? Want to confirm whether it's in the 'find the library' or 'find the function' side of things.

System.loadLibrary didn't want to take a path, but specifying an absolute path using System.load gives the same error,

TheLastRar commented 1 year ago

Also, testing the original example without specifying a java.library.path gives Exception in thread "Thread-0" java.lang.UnsatisfiedLinkError: no JNITestNative in java.library.path So it seems to be able to find the library just fine

wasabii commented 1 year ago

Yeah. So, I managed to build a native lib, and get java.exe with -Djava.library.path=pathtodir -cp pathtodir Test working, loads library fine, loads function fine too.

So I'm sort of still searching for the thing you're doing that I'm not.

TheLastRar commented 1 year ago

I can upload the vs project if that would help

wasabii commented 1 year ago

Yes please.

TheLastRar commented 1 year ago

JNITestNative.zip

Edit: Let me know if you can reproduce it with that

wasabii commented 1 year ago

So, the issue.

Fun one. The DLL you built depends on a few native Windows things which are not otherwise loaded into the .NET Core process. I believe it was the later version of MSCVRT. The search path for dependent libraries on Windows, using LoadLibraryEx, would normally include System32, where that DLL is located. However, as part of the clang changes, the loading code got changed to allow the DLL to be located alongside the source DLL. And that change REMOVED it's attempt to search System32. Added that back. Error on my part. Didn't notice it because we target an older MSVCRT in the libraries we generate and use internally (we need to match compatibility with .NET Core 3.1). Since those DLLs already have the right version of MSVCRT loaded (by virtue of running inside .NET Core itself), no attempt to load an alternate version was made.