Updated DLL causes JNI to throw "Exception c0000005"
Here's my problem.
I have a third part DLL (to which I do not have the source) that I have to use JNI to talk to. The people that supply this DLL are not a Java-house. I discovered a bug in their DLL, so wrote some C++ which exercised their DLL, exposed the bug and sent it to them for a fix. I finally got an updated DLL back from t开发者_如何转开发hem, ran my C++ code (which worked fine) and discovered that bug had indeed been fixed.
However, now when I use this new DLL inside my JNI code I get the following exception thrown;
Exception c0000005, at 1EEE3416
Access violation: attempting to read memory at address 00000004
Native function stack data: 0,3f49c0,20201,801c6,65637845,6f697470,3063206e,30303030
com.jniwrapper.FunctionExecutionException: c0000005
at com.jniwrapper.Function.invokeCFunc(Native Method)
at com.jniwrapper.FunctionCall.a(SourceFile:127)
at com.jniwrapper.FunctionCall.call(SourceFile:35)
at com.jniwrapper.Function.invoke(SourceFile:188)
at com.tme.techdoc3.diagnostic.api.denso.DensoApiInvoker.invoke(DensoApiInvoker.java:78)
at com.tme.techdoc3.diagnostic.api.denso.NewDensoApi.invoke(NewDensoApi.java:106)
at com.tme.techdoc3.diagnostic.api.denso.NewDensoApi.connect(NewDensoApi.java:46)
at ConsoleApiRunner.main(ConsoleApiRunner.java:59)
I'm actually using JNIWrapper to provide my JNI code and so to rule their product out as causing a problem I wrote my own JNI code instead; but I still get this same error. This convinces me that the problem is in the third party DLL.
I'm getting this exception from the very first function I call on the DLL (incidentally, this function did not have the bug in it...).
The place we get the DLL from has expressly said that they will not support it's use in a JNI environment, even so far as they will not send me any kind of release notes or list of changes between the fixed and non-fixed DLLs.
Politically, there is nothing I can do about this. Practically, I'm limited to this supplier for the DLL.
Can anyone think of any reason why this DLL would work when called from C++ but not when called in JNI? I've been playing with the JNI stack size (-Xss) and some other JVM parameters, but I've either not hit on the right settings yet or I'm looking at the wrong thing.
Any ideas are greatly appreciated.
Many thanks.
EDIT: Adding in my own JNI code to see if someone can spot a mistake.
EDIT 2: Corrected code copy-n-paste error.
When I use my own JNI code, here's the implementation of the .cpp file I'm using;
#include "stdafx.h"
#include "windows.h"
#include "MyJniApi.h"
#include "ThirdParty.h"
#pragma comment(lib, "ThirdParty.lib");
ThirdPartyThing* thirdParty;
JNIEXPORT jlong JNICALL Java_com_mycompany_jni_MyJniApi_connect(JNIEnv *, jobject) {
long connId = 0L;
thirdParty = new ThirdPartyThing();
long retval = thirdParty->GetConnection(&connId);
if(0 == retval) {
return connId;
} else {
return retval;
}
}
As you can see, it's pretty simple and I can't see any place there when I've got my pointers etc mixed up. (Disclaimer: this is pretty much the sum of me C++ skills!)
c0000005 indicates an "access violation" this usually means that a pointer has been used that holds an invalid memory address. This can just be a bad pointer value e.g. uninitialised or may indicate that the object has been destroyed.
I would look at two things:
The arguments you are passing in particular any out types. I haven't used JNI directly but I imagine a variable may be bridged to C++ differently if it is readonly rather than if it can be written to. Be sure that any buffers you are passing are allocated if the DLL API expects them to be already allocated.
The lifetime of objects you are calling methods on or passing as arguments. Make sure the Java objects you are working with are not being collected during the call to C++.
My suggestion is based on this assumption - if you can get it working in C++ then you should be able to get it working in JNI.
It's been a long time since I used JNI but problems like this are usually caused by the simplest of things.
What I would check very very thoroughly is that you are using all the updated .h header/.lib etc files that came with the new DLL. Regenerate your JNI definition object after checking that you are pointing to all the new files, the correct paths (including your current JRE). Search your entire file system and delete any previous versions of the old DLL and it's dependencies/headers/libs/.obj etc. One stale file could be causing the problem.
I once wasted three days on a problem because some app put a copy of a core windows DLL in it's own program directory (and then added to PATH), which caused mayhem when trying to load the correct one.
BTW: does the DLL have any weird authentication/licensing behavior? or does it need to load other dependencies that it cannot resolve?
Okay, this has been resolved (rather than solved).
Recently I realised that I had introduced a red herring along the way. When I wrote my own JNI code (to rule out the JNIWrapper product causing problems) and announced that the exception was still thrown, I must have been stuck in one of the circles of DLL Hell. When I first introduced by own JNI code, the exception was thrown, however in subsequent days, re-running my own JNI code did not throw the exception. So I assume I must have had an old DLL laying around somewhere causing some erroneous results.
So new information: The exception is thrown when used with JNIWrapper but not with home-grown JNI code.
So now I dug deeper in JNIWrapper. In one of their support forum posts somewhere it says that JNI wrapper is not designed for C++ DLLs, namely it only supports a sub-set of the C++ language features. Virtual methods being a particular shortfall. Since my third-party DLL is a C++ one, I figure that in the previous version they were using not using JNIWrapper-unsupported language features, but now they are. To me, this means that I can no longer use the JNIWrapper tool.
Instead I'm using Swig to generate all the JNI code I need. Swig looks like it's a better choice that JNIWrapper anyway, since the resultant Java code is much cleaner.
Thanks to everyone who gave suggestions. I think that at least one aspect of every answer was correct and helpful.
精彩评论