JNI problem: Calling java from C++ dll

K

kowald

Hello everybody,

I try to call java methods from a C++ dll usin JNI and have some
problems I don't understand.
This is under XP using Java 1.5.06


If a function "x" of the dll is called I want to create the JVM and
get a reference to the class I intend to use:

jint res = JNI_CreateJavaVM(&jvm,(void**)&env,&vmArgs);
jclass jclassTmp = env->FindClass("myClass");
jSimuClass = (jclass)(env->NewGlobalRef(jclassTmp));

I want to use the JVM and class later when a different function inside
the dll is called. Therefore I created a global reference for my class
and use global variables for env and jvm in my dll

JNIEnv *env;
JavaVM *jvm;
jclass jSimuClass;


If now the function "y" of the dll is called, I try to get a method ID
doing:

methodID = env->GetMethodID(jSimuClass, "method1", "(I)V");

AND THIS CRASHES THE C++ PROGRAM right at this line of code (it does
not return from this call). If I place this line of code in the dll
function x, right after the creation of jSimuClass it works. If I try
in function y other JNI methods like

jclass jclassTmp = env->FindClass("myClass");

this also works, so env is still valid. The question is why is
jSimuClass no longer valid?

If the C++ part is not a dll, but a normal executable it also works. I
can create the JVM in a function call and then call GetMethodID in a
different function call. I'm now a bit clueless and any hint what could
be wrong or what is special about a dll is welcomed.

Axel
 
B

Bill Medland

Hello everybody,

I try to call java methods from a C++ dll usin JNI and have some
problems I don't understand.
This is under XP using Java 1.5.06


If a function "x" of the dll is called I want to create the JVM and
get a reference to the class I intend to use:

jint res = JNI_CreateJavaVM(&jvm,(void**)&env,&vmArgs);
jclass jclassTmp = env->FindClass("myClass");
jSimuClass = (jclass)(env->NewGlobalRef(jclassTmp));

I want to use the JVM and class later when a different function inside
the dll is called. Therefore I created a global reference for my class
and use global variables for env and jvm in my dll

JNIEnv *env;
JavaVM *jvm;
jclass jSimuClass;


If now the function "y" of the dll is called, I try to get a method ID
doing:

methodID = env->GetMethodID(jSimuClass, "method1", "(I)V");

AND THIS CRASHES THE C++ PROGRAM right at this line of code (it does
not return from this call). If I place this line of code in the dll
function x, right after the creation of jSimuClass it works. If I try
in function y other JNI methods like

jclass jclassTmp = env->FindClass("myClass");

this also works, so env is still valid. The question is why is
jSimuClass no longer valid?

If the C++ part is not a dll, but a normal executable it also works. I
can create the JVM in a function call and then call GetMethodID in a
different function call. I'm now a bit clueless and any hint what could
be wrong or what is special about a dll is welcomed.

Axel
Could it be a problem with threading? Is it possible that you are trying to
use jSimuClass in a different thread from the one that was current when it
was allocated?
 
K

kowald

Could it be a problem with threading? Is it possible that you are trying to
use jSimuClass in a different thread from the one that was current when it
was allocated?

Hm, I'm not sure. The DLL that calls the java class is a plugin for a
commercial application for which I have no source code. So I don't know
when and from where my dll is called.

But if jSimuClass would be called from a different thread, why would
this be a problem ? What could happen? The error code I'm getting when
the C program crashes is something like:
"There was an unhandled exception. Access error when trying to read
address 0x00000090"

Axel
 
C

Chris Uppal

JNIEnv *env;

It's usually a bad idea to store a JNIEnv pointer as a static, unless your
program is driving Java rather than being driven by Java.

A JNIEnv is only valid in one thread.

If your code has been called by Java, then that will provide a JNIEnv which you
should use (even if you are on the same thread as the one which saved the
original JNIEnv), since not all operations are valid on anything except the
current JNIEnv (I can't remember the details, I'm afraid -- the only /specific/
problem I remember is that JNI local refs must be released using the same
JNIEnv as created them).

If your code might be called in a different thread then you'll have to take
account of that in your design, and ask the JVM for the correct JNIEnv for
whatever thread you happen to be running on. That's easier, of course, if you
are in control of the app's theading architecture.

BTW, just because some code works in some situations doesn't mean that code is
correct -- it may only mean that you got lucky (or unlucky, depending on how
you see it).

-- chris
 
B

Bill Medland

Chris said:
It's usually a bad idea to store a JNIEnv pointer as a static, unless your
program is driving Java rather than being driven by Java.

which was clear from the original post.
A JNIEnv is only valid in one thread.

but as I remember it, is guaranteed to be valid on all calls in that thread
If your code has been called by Java, then that will provide a JNIEnv
which you should use (even if you are on the same thread as the one which
saved the original JNIEnv), since not all operations are valid on anything
except the current JNIEnv (I can't remember the details, I'm afraid -- the
only /specific/ problem I remember is that JNI local refs must be released
using the same JNIEnv as created them).

I'd be interested in the details.
 
B

Bill Medland

Hm, I'm not sure. The DLL that calls the java class is a plugin for a
commercial application for which I have no source code. So I don't know
when and from where my dll is called.

But if jSimuClass would be called from a different thread, why would
this be a problem ? What could happen? The error code I'm getting when
the C program crashes is something like:
"There was an unhandled exception. Access error when trying to read
address 0x00000090"

Axel
Almost certainly that involves accessing a structure member where the
pointer to the structure is null. Sounds to me like something is
uninitialised.
 
C

Chris Uppal

Bill Medland wrote:

[me:]
I'd be interested in the details.

I'm sorry, but I can't remember where in the spec it is, and a quick search
didn't locate it. If it's going to come down to re-reading the entire spec
looking for it then you can do that as easily as I ;-)

This came up when I was setting up my JNI stuff some years ago. I tried
porting my code to run with the IBM JMV, and it (helpfully) complained that I
was releasing local refs on the wrong JNIEnv. I didn't believe that there was
such a restriction. So I swore, and went looking in the spec for proof that
IBM was wrong -- unfortunately, what I found was proof that IBM was right
:-( So I swore even more, and then almost completely re-wrote the
housekeeping in the lower layers of my stuff to obey the "new" rule. As a
side-effect of that, my stuff now uses the "current" JNIEnv for all operations,
not just DeleteLocalRef() -- which is why I'm not all that interested in what
other restrictions there may be (if there are any at all), and the details have
faded from my mind.

Incidentally, I agree with your suggestion (elsethread) that the error message
the OP has now provided is indicative of an attempt to deference a NULL
pointer.

-- chris
 
B

Bill Medland

Chris said:
Bill Medland wrote:

[me:]
I'd be interested in the details.

I'm sorry, but I can't remember where in the spec it is, and a quick
search
didn't locate it. If it's going to come down to re-reading the entire
spec looking for it then you can do that as easily as I ;-)

True. BTW what do you regard as "the spec"? I tried using the JNI
documentation that comes with Java and forgot that I had downloaded Sheng
Liang's "Programmer's Guide and Specification" which I find much better.
This came up when I was setting up my JNI stuff some years ago. I tried
porting my code to run with the IBM JMV, and it (helpfully) complained
that I
was releasing local refs on the wrong JNIEnv. I didn't believe that there
was
such a restriction. So I swore, and went looking in the spec for proof
that IBM was wrong -- unfortunately, what I found was proof that IBM was
right
:-( So I swore even more, and then almost completely re-wrote the
housekeeping in the lower layers of my stuff to obey the "new" rule. As a
side-effect of that, my stuff now uses the "current" JNIEnv for all
operations, not just DeleteLocalRef() -- which is why I'm not all that
interested in what other restrictions there may be (if there are any at
all), and the details have faded from my mind.

Oh; OK. I knew about that one (having read it more recently than you, I
expect). I was just getting an impression that you were suggesting that we
could not depend on the JNIEnv staying constant on a given thread, which I
thought was guaranteed (and thus allowed caching in a single-threaded
program).
Incidentally, I agree with your suggestion (elsethread) that the error
message the OP has now provided is indicative of an attempt to deference a
NULL pointer.

Yes. But I don't think it is the JNIEnv that is null.

Can the OP instruct the JVM to run with all that JNI protection code enabled
(the verbose:jni I presume; I have forgotten)
 
C

Chris Uppal

Bill said:
BTW what do you regard as "the spec"? I tried using the JNI
documentation that comes with Java and forgot that I had downloaded Sheng
Liang's "Programmer's Guide and Specification" which I find much better.

In my case it would have been the version of the "JNI Specification" (plus
ammendements) which came with the JDK 1.3. Obviously, I use the version which
comes with 1.5 these days ;-)

As far as I know, Liang's book includes the spec in toto, but I haven't checked
it word-for-word, and I don't know which version of the spec it is anyway.

Can the OP instruct the JVM to run with all that JNI protection code
enabled (the verbose:jni I presume; I have forgotten)

-Xcheck:jni

That's certainly worth trying. One word of warning is that I think the
checking code in at least one version of 1.5 was buggy and reported errors
where there was none. At least, I have some code which an earlier dot.dot
release reported as wrong, but I can't find anything wrong with it, and neither
1.4.x nor later versions of 1.5 report any problem. (I'm currently usng
1.5.0_06-b05).

Another thing that's worth trying if the OP has access to a sufficiently
up-to-date IBM JVM, is to try that. The IBM error checking is (or was when I
last tried it -- back in 1.3 days) superior to Sun's.

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top