So as described above I am trying to copy an int object into off-heap memory with the help of Unsafe. Here is my main function:
public static void main(String[] args) throws Exception {
UnsafeHelper hlpr = new UnsafeHelper();
int original = 100;
long copyaddress = hlpr.shallowCopy(original);
System.out.println("COPIED TO ADDRESS: " + copyaddress);
int copy = (int) hlpr.fromAddress(copyaddress);
getCopiedObject(copyaddress);
}
it provides me the address of the beginning of the copied object (copyaddress
).
Next, i want to pass this address to the function defined in jni agent. Here is the declaration of the native function in the java class:
private static native void getCopiedObject(long address);
Here is the declaration of the function in agent.h:
JNIEXPORT void JNICALL Java_main_Main_getCopiedObject(JNIEnv *, jlong);
And here is where i get into the trouble... The long value which i get in the C++ function is different from the one which i pass in java...
JNIEXPORT void JNICALL Java_main_Main_getCopiedObject(JNIEnv *env, jlong address){
...
unsigned long long a = address;
signed long long b = address;
printf("UNSIGNED LONG LONG %llu \n", a);
printf("SIGNED LONG LONG %lld \n", b);
...
}
In my case java long's size is 64bit, so i use long long
in my c++ code... I tried both the signed and unsigned conversions but it never worked...
So when i run this code i get following outputs:
JAVA:
COPIED TO ADDRESS: 1487190592
AGENT:
UNSIGNED LONG LONG 37025744
SIGNED LONG LONG 37025744
According to the output, i am converting jlong to long in a wrong way...
Does anybody know how to get the correct long long
value from a jlong
?
I seem to have figured out what the problem is. When you have a static native
method there are 2 extra arguments besides the one you have in Java. The first is the JNIEnv
and the second is a jclass
.
I don't know how exactly you generated your .h
file, but when I use:
javah -jni Main
I get the signature:
JNIEXPORT void JNICALL Java_Main_passLong(JNIEnv *, jclass, jlong);
In the .h
file. If I use it like this, it behaves as expected. So my solution would be to add a jclass
parameter before the jlong
.
If I remove the jclass
parameter, I see the wrong value. I guess the JVM does not check the signature of the native method when loading the library.