16

I have created a C++ module to build into a shared library file and then call it from Java using JNI.

I have 2 environments, Windows and Unix and I have a C++ executable program and a Java program that I just recompile for each environment.

  • When I compile my tester.exe program in Unix and run it using methods from my library (.so) it works fine.
  • When I compile my Java program in Unix and load my library (.so) with Java's loadLibrary, it works fine.
  • When I compile my tester.exe program in Windows and run it using methods from my library (.dll) it works fine. Just like the unix version.

  • When I compile my Java program in Windows and load my library (.dll) with Java's loadLibrary it fails. It says Attempt to access invalid address.

I cannot figure out why it will not work with the Java loadLibrary when running in Windows, but it works everywhere else using the same code. If I delay load a dependent DLL that my library uses, then my library loads in Java but is not functional. I know there is specific code that causes the issue with Java loading my library, but I can't figure out why my C++ exe has no problem with the same methods and libraries.


My dll has 1 exposed method which calls 4 methods from some existing libraries. If I comment those 4 methods out, then my dll loads in Java fine. I know it's something to do with these methods from a library my dll links to. Is there something different with how Java sees the dependent libraries? I've tried loading the dependent libraries first, but one of the dll files I load causes a recursion error and the stack overflows.

Anyone know a way around a DLL that causes a stack overflow from a recursion error? I need the methods in it, but I cannot load it with java loadLibrary.


Here is more detail about the files involved and the actual error message. I added a DllMain to my inital dll file just to see what loads and when. If I compile that same program (my_plain_dll_to_call_JNI_DLL) as an exe file, everything works fine. If I compile it and load it from my java program this happens.

  • myJavaProgram, simply calls System.loadLibrary() to load a basic .dll file that calls a method in my other dll that contains JNI code.
  • my_plain_dll_to_call_JNI_DLL is a dll I created by linking it to my dll library file just to test the dependency. It just calls a method from the other dll which is calling the native code I need.
  • my_JNI_DLL.ll is a dll file linked with existing C++ programming libraries that I need to access from JNI. It contains direct calls to methods in existing source code libraries.

I wrote the filename displaying the text to the left of each line to show what layer the execution is in.


c:\java myJavaProgram
myJavaProgram: Java Static Method Entry.

myJavaProgram: Java Calling System.loadLibrary(my_plain_dll_to_call_JNI_DLL)

my_JNI_DLL.dll: Entering DllMain

my_JNI_DLL.dll: DLL_PROCESS_ATTACH

my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_THREAD_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_THREAD_DETACH
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_DETACH

myJavaProgram: my_plain_dll_to_call_JNI_DLL Loaded!

myJavaProgram: Java Static Method Exit.

myJavaProgram: Entering Main().

my_plain_dll_to_call_JNI_DLL: In call_my_JNI_DLL_method

my_JNI_DLL.dll: In my_JNI_DLL_method

my_JNI_DLL.dll: Entering my_JNI_DLL_CheckEnvironmentVariables()

my_JNI_DLL.dll: Exiting my_JNI_DLL_CheckEnvironmentVariables

my_JNI_DLL.dll: Calling StartExistingNativeCode.

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (0xc0fb007e), pid=7500, tid=7552
#
# JRE version: 6.0_21-b06
# Java VM: Java HotSpot(TM) Client VM (17.0-b16 mixed mode, sharing windows-x86 )
# Problematic frame:
# C  [KERNELBASE.dll+0x9673]
#
# An error report file with more information is saved as:
# C:\hs_err_pid7500.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_DETACH

my_JNI_DLL.dll: Entering DllMain

my_JNI_DLL.dll DLL_PROCESS_DETACH


Update I've narrowed down the issue to a memory management library that is linked in from another dll that my program uses. The dll that it uses is sh33w32.dll, it's called SmartHeap and is by a company named Microquil I think. I have version 3.3, and when Java LoadLibrary tries to load that dll, it fails. I'm not sure what I could do to have java handle loading that library. It must have something to do with the area of memory that Java can access, versus what windows allows an exe to access. The exe has no problem with the SmartHeap library, but Java will not allow me to use it. Any ideas or experience dealing with this? I've tried to remove the linked library by recompiling the other libraries, but then the normal calls in the code fail that normally work.


Additional Information Found The function that is in the dll that fails to load in java is called MemRegisterTask. It's from a product called SmartHeap by Microquill. Here is the documentation I found about this function. I think this memory allocation is what causes java to fail to load it.

MemRegisterTask initializes the SmartHeap Library. On most platforms, you don’t need to call MemRegisterTask because SmartHeap will initialize itself when you make the first call.

SmartHeap maintains a registration reference count for each task or process. Each time you call MemRegisterTask, this reference count is incremented. If your last call to SmartHeap occurs before your application is ready to terminate, you can call MemUnregisterTask to terminate SmartHeap. MemUnregisterTask decrements the registration reference count by one — when the count is zero, SmartHeap will free any SmartHeap-allocated memory and debugging state associated with the current task or process.

Logan
  • 2,369
  • 19
  • 20
  • Maybe posting some code would help people to see more into this. Just a quick check: you are exposing properly your DLL to java (ex.: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html#impl) – JScoobyCed Apr 06 '12 at 15:11
  • I'm not sure I can post code, because of work rules. I've worked through every other JNI error I've ran into, so I'm trying to understand the concepts to see if I can see why it's failing. I am exposing the 1 method my java program uses correctly. The problem is the dll doesn't even load in Windows Java, Unix Java works fine. – Logan Apr 06 '12 at 15:30
  • It seems like from the exception message that either the paramewters to the C++ function are incorrect (marshalled into a different type than expected), or the linking is not done properly. It is possible that the C++ library was compiled with different calling conventions than what JNI provides/assumes. – Attila Apr 06 '12 at 18:08
  • Did you compile the Windows binary in 32-bit and try to use a 64-bit VM? Or Vice-Versa? Also be sure you are using the correct memory management binaries. – Andrew T Finnell Apr 06 '12 at 19:43
  • Now that you mention it, when I compile in Unix, everything is fine, but when i compile in Windows I get warning messages about losing precision. The jlong from the jni.h is defined as _int64, and I think the long in C is 32 bit? How do I prevent that warning? – Logan Apr 06 '12 at 19:48
  • @Logan should be a fast check. Download the 32-bit JVM and see if your program runs successfully. – Andrew T Finnell Apr 06 '12 at 19:51
  • 2
    It looks like my JVM is 32-bit. So is the Borland 5.5 compiler I'm using for the C code. The borland compiler is giving me that warning and it's 32-bit too. We do have a library that manages memory that gets linked into my native code that is the cause of the failure. I can load every dependent dll except 1 and it gives me a java recursion error and something about the stack overflows. I don't know how to get around that though, it gets linked in as soon as I link to our existing library files. – Logan Apr 06 '12 at 20:09
  • Re the update, are you saying that you are trying to load that sh33w32.dll directly with loadLibrary(), or that you are loading some other DLL that in turn needs sh33w32.dll? – Dmitry Leskov Apr 21 '12 at 12:33
  • I tried to load that sh33w32.dll directly, thinking maybe it was a dependency that needed to be loaded first, but that didn't work either. My dll references functions in another dll and that dll is the one that is linked to the sh33w32.dll file. It looks like it fails when it is allocating memory for the C code. I changed my dll to load the methods dynamically now, so my dll loads, but the calls to the C functions fail. – Logan Apr 22 '12 at 22:14

2 Answers2

1

Anything useful in the hs_err ... log file. Usually there's a stack backtrace etc. pointing something out.

Also tried to run java.exe (with parameters running a test that loads the stuff) inside the debugger?

From trace above one can see loading seems to work fine (the trace output suggest that dllentrypoint/dllmain has been augmented w/ trace output by you).

Sequence in loading is the following:

  1. load dependent dlls
  2. load dll itself
  3. call the dllentrypoint/dllmain w/ process attach

So this is already beyond loading the DLL.

Have you checked whether you are using debug/release runtimes from Windows? Debug may clash with release - Java is release, your sample exe likely was same as your dll build.

schroder
  • 181
  • 1
  • 3
  • I pretty much have every combination of release and debug that I could possibly have. To make a release version DLL do I just have to turn debugging off? I've read about this, but wasn't sure sure how to go about it. I've been able to load my dll now by dynamic linking to the code I need, but the code I need to execute fails anyway. So dynamic vs static linking did not make a difference. I also read about using byte arrays for memory, but not sure how to do that when I'm just loading the dll to start with. – Logan Apr 26 '12 at 00:03
  • I've gone through the hs_err log files, read articles online on how to read those, but nothing ever showed as the problem. Interesting thing though, I thought kernelbase.dll was failing, but yesterday I ran my code and threw a null pointer exception from the C code. It created the same hs_err log that I get when I run my code. As I type this, it makes me wonder if there truly is a null somewhere. Why would it work in windows as an exe though if there's a null value? Plus why would it fail on loadlibrary... – Logan Apr 26 '12 at 00:06
0

Looks like a calling convention or type size mismatch to me. Each Windows C compiler has its own set of peculiarities, and the Windows JNI headers assume (a recent version of) Microsoft Visual C++. Look at the warnings closely - loss of precision is bad sign.

For instance, __int64 is MSVC-specific. You need to find out what is the name of the 64-bit integer type in Borland C and map it to __int64 before including jni.h.

Dmitry Leskov
  • 3,233
  • 1
  • 20
  • 17
  • The __int64 type in Borland is LongLong, and it looks like it's already defined. Do think think that would prevent my DLL from loading? I changed my dll to dynamically link to the other dlls now, but now the code fails in java, eventhough the dll will load in java. The same dll code works fine still when referenced from a c++ exe file. It has to be something with how Java allows access to memory. I just can't find any good information about that. – Logan Apr 24 '12 at 01:35
  • I woudl still suggest to trace the warnings to the root cause. Also, did you try running your app with -verbose:jni? On a JVM other than HotSpot? – Dmitry Leskov Apr 25 '12 at 09:30
  • I have tried running with -verbose:jni, it just gets to my code then fails to execute the commands that are from the dll I need to use. I'm pretty convinced this is a memory issue at this point. It sounds like this one DLL that is linked in is trying to allocate memory. When java tries to load it, it gets a recursion error and the stack overflows. There's only 1 method in this dll that actually gets used, but loading it blows the stack. – Logan Apr 25 '12 at 23:59
  • Stack overflow often means calling convention mismatch. I.e. when the function returns, it gets a value from the stack that is not a return address but the address of some other function, then things get really messy. Can you trace the supposedly offending function under a debugger? – Dmitry Leskov Apr 26 '12 at 11:37
  • I've tried to debug the dll, but I can't get the debugger in Eclipse to work and my Borland TurboDebugger will not attach to a process for some reason. The methods that fail are allocating memory in C, so I've heard that doesn't work well in Java. I'm not sure why it's trying to allocate memory when it loads a dll unless there's a static method running or something. – Logan Apr 27 '12 at 02:39
  • You'll need a low-level debugger for that. There is WinDbg in Windows SDK, but you can also [download Windows debugging tools separately](http://msdn.microsoft.com/en-us/windows/hardware/gg463009). The debugger that comes with our legacy [Native XDS-x86](http://www.excelsior-usa.com/xdsx86.html) product (freeware) may also work, as your app is 32-bit. – Dmitry Leskov Apr 27 '12 at 11:13