Reputation: 987
in my program C is called from Java, C functions can be called outside of a Java context but sometimes need some Java ressources. I should explain what the program is... So the C library is a plugin system which can load C plugins, plugins sometimes need to access to Java ressources, for example to retrieve a String id.
So when the plugin system is loaded, an init function is called by the JNI so the JNIEnv *
and jobject
can be stored for further access by the plugins.
In the java class I have provided instance method to access to those ressources, for example I have method
private String getId() {
return "Bryan";
}
The C plugin system have a function
char *get_id(char *id) {
jobject jobj = (*jvm.env)->CallObjectMethod(jvm.env, jvm.this, jvm.getId);
jstring jid = jobj;
if (jid == NULL)
debug("get_id", RED "jid NULL");
else
debug("get_id", RED "jid not null"); */
debug("get_id", RED "in get_id, method called");
const char *cid = (*jvm.env)->GetStringUTFChars(jvm.env, jid, NULL);
debug("get_id", RED "converted to c string: %s", cid);
strcpy(id, cid);
debug("get_id", RED "string copied");
(*jvm.env)->ReleaseStringUTFChars(jvm.env, jid, cid);
debug("get_id", RED "string released");
return id;
}
Where jvm is a structure containing the field env
and obj
corresponding to the JNIEnv *
and jobject
stored at initialization, and jvm.getId
which is the methodID
of the getId
Java instance method inizialized at the same time.
The debug macro is just a call to printf
with a flush
which help me to debug the program.
And that is the output after a call to get_id
:
DEBUG IN plugin_system.c LINE 339:
In get_id
in get_id, calling method...
DEBUG IN plugin_system.c LINE 343:
In get_id
jid NULL
DEBUG IN plugin_system.c LINE 346:
In get_id
in get_id, method called
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007fb6bcb6cd70, pid=25254, tid=0x00007fb6974be700
#
# JRE version: OpenJDK Runtime Environment (8.0_92-b14) (build 1.8.0_92-b14)
# Java VM: OpenJDK 64-Bit Server VM (25.92-b14 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x675d70]
#
# Core dump written. Default location: /home/kowa/code/reseaux/projet/ringo/java/bin/core or core.25254
#
# An error report file with more information is saved as:
# /home/kowa/code/reseaux/projet/ringo/java/bin/hs_err_pid25254.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
[4] 25254 abort (core dumped) java Jring Nick 9999 8888 1
As you can see the call to Java getId
is (looks) successfull, but a core dump is triggered by GetStringUTFChars
.
What's wrong ?
Upvotes: 3
Views: 441
Reputation: 1
You can not cache the JVM's env
. See Keeping a global reference to the JNIEnv environment, especially this answer:
The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.
Updated link. The link in the other answer is stale.
As far as the Java object, class, and method id, you need to obtain a global reference to those if you're going to cache them. See What is 'JNI Global reference' and Caching JNI objects and thread-safety (in Android)
Upvotes: 1