3

Firstly, I want to say that the old answers doesn't work (for example, GetDirectBufferAddress function in below answers want one parameter now) at the moment as here:

JNI - native method with ByteBuffer parameter

and here,

how to write and read from bytebuffer passing from java to jni

It would be better if someone helps..

So, I can't send correctly my ByteBuffer, which's some elements filled, to C from Java using JNI and I can't return that ByteBuffer's elements again to C

My native function decleration:

public native int myfunc(ByteBuffer pkt);

Allocation for it

private ByteBuffer pkt = ByteBuffer.allocate(1000);

I am calling it in this way:

System.out.println(myfunc(pkt));  // Doesn't works, throws exception
pkt.position(0);
System.out.println(pkt.get()); // works, when I do comment line above .println

And my C codes as below:

JNIEXPORT jint JNICALL Java_xxx_myfunc(JNIEnv *, jobject, jobject); // header


JNIEXPORT jint JNICALL Java_xxx_myfunc(JNIEnv *env, jobject obj, jobject pkt) // function
{
  jbyte *buff = (jbyte *) env->GetDirectBufferAddress(pkt);
  // buff[0] = 0; I've also tried in this way
  return buff[0];
  //return 1; if I return 1, it returns correctly
}

when I run the java program it throws exception. How can I return my filled ByteBuffer values from C?

EDIT

A fatal error has been detected by the Java Runtime Environment:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x719c16b8, pid=1096, tid=1900
den yan
  • 33
  • 1
  • 5
  • Can you post the stacktrace? – Emax Nov 08 '17 at 09:32
  • @Emax I am using different pc to coding but edited question as trace's start – den yan Nov 08 '17 at 09:55
  • Ok but where did you allocate `pkt` ? Your question is lack of [mcve]. By the way, all examples show that you **must** send `env` as first parameter `env->GetDirectBufferAddress(env, buf)` Do you have warning when you compile ? – Stargateur Nov 08 '17 at 10:33
  • @Stargateur sorry I had forgotten, but I edited for allocation line now. And as I specified in the question I cannot enter two parameter for GetDirectBufferAddress function. And I am not sure what buf is. Isn't buf is my pkt parameter? And no, there is no warning. I think, if there would be a problem in my functions I couldn't return 1 value to Java or couldn't print ByteBuffer's first parameter – den yan Nov 08 '17 at 10:40
  • 1
    If you can survive with accessing values one by one, take a look here: https://github.com/mkowsiak/jnicookbook/tree/master/recipeNo040 – Oo.oO Nov 08 '17 at 10:46

2 Answers2

11

To use GetDirectBufferAddress() you must guarantee that pkt is direct (you can check this with isDirect()). The easy way to obtain such object is ByteBuffer.allocateDirect(). Direct ByteBuffer can be created from C++, too.

The difference between direct and indirect ByteBuffer is clearly explained in the Java oficial doc.

Update I see your update. No, ByteBuffer.allocate(1000) does not produce a DirectByteBuffer.

As @Tom Blodget correctly noted, the JNI spec explicitly says that GetDirectBufferAddress() can return NULL. This works both ways: the call itself should not crash if pkt is an indirect ByteBuffer, but you must check the result even if you are sure that pkt is a DirectByteBuffer.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • 1
    Doing the "C" thing of checking the result of `GetDirectBufferAddress()` for `NULL` (per the [documenation](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#GetDirectBufferAddress)) would cover more cases than `isDirect()`. – Tom Blodget Nov 08 '17 at 23:52
  • @TomBlodget the "C" thing would not be to check `NULL` or `isDirect()`, is the user function responsibility to give correct argument (ofc course function must explicitly ask this kind of argument in doc) ;) – Stargateur Nov 09 '17 at 07:40
0

You can't use GetDirectBufferAddress() except on a direct byte buffer. You don't have a direct byte buffer.

user207421
  • 305,947
  • 44
  • 307
  • 483