Reputation: 23
I'm calling a C function through JNI which will return a byte array. This worked like a charm until I tried to clean up the accessing Java class by removing unneccessary debug output I was printing to the console. One of these outputs was being generated between the JNI call and accessing the array returned by it:
long ctime = System.currentTimeMillis();
byte[] arrayFromC = _wrapperObject.someMethod(someByteArray, k, n);
System.out.println(System.currentTimeMillis()-ctime);
byte[] newByteArray = doSomething(arrayFromC, n);
When I removed the println call, I suddenly started getting segmentation faults:
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007fe1d410f751, pid=6875, tid=140607705560832
#
# JRE version: OpenJDK Runtime Environment (7.0_51) (build 1.7.0_51-b00)
# Java VM: OpenJDK 64-Bit Server VM (24.45-b08 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x5c8d51] jni_GetByteArrayElements+0x61
The segmentation fault is triggered when the JRE tries to execute the last line of code shown above. If I try to replace this with any other operation accessing the array (such as merely assigning the first array element to a variable), this will also trigger a segmentation fault.
This is how I am returning the array in the C function:
// c[] is a char array of length mlen which at this point has already been filled by a library call
jbyteArray out = (*env)->NewByteArray(env, mlen);
jbyte *jBuf = (jbyte *)calloc(sizeof(jbyte), mlen);
for (int i = 0; i < mlen; i ++) {
jBuf[i] = (jbyte)c[i];
}
(*env)->SetByteArrayRegion(env, out, 0, mlen, jBuf);
free(jBuf);
return out;
And this is what the method in the wrapper class does (basically removing some zero-padding which the C library I am using adds to the array and then returning it):
byte[] cpadded = jni_c_function(mpadded, mpadded.length, n, k);
return Arrays.copyOfRange(cpadded, CZEROBYTES, cpadded.length);
I can avoid the segmentation fault by either printing my debug output between making the JNI call and accessing the array or just calling this.wait(10), so I suspect that the JNI call may actually be returning before it actually got round to filling the array's memory area. I can't seem to find any documentation and/or similar questions about this behaviour though, as I would expect if this was the case.
Any ideas on how to fix this without printing unneccessary stuff or just waiting for an arbitrary time?
Upvotes: 2
Views: 1105
Reputation: 57183
I am not sure why this could resolve the segfault, but your C code performs too many redundant steps. Try this:
jbyteArray out = (*env)->NewByteArray(env, mlen);
(*env)->SetByteArrayRegion(env, out, 0, mlen, (jbyte*)c);
return out;
Upvotes: 1