cmemory-leakscallbackjava-native-interfacejna

When using JNA, if I receive a char* value through calling a Java method callback, how can I free it?


The native code looks like this:

typedef char *(*getJavaString)();

getJavaString getJavaStringFunc = nullptr;

void registerGetJavaStringFunc(getJavaString func) {
    getJavaStringFunc = func;
}

void someCContextFunc() {
    char* value = getJavaStringFunc();
    // How do I free the value? Can I use `free(value)` directly?
}

I first call registerGetJavaStringFunc in Java to register a Java function with C. In the future, I will call the getJavaStringFunc function to get a value in the C context. However, how can I free the value?

I initially wrote the code to free the 'value' directly, as shown below:

char* value = getJavaStringFunc();
free(value);

This method appeared to work just fine. However, upon consulting with ChatGPT, I was informed that there could be potential risks involved. ChatGPT advised me to register a new function called 'freeJnaValue' within the C context and use that function to free the 'value' instead. At this point, I am uncertain about which approach is more appropriate and what my next steps should be.


Solution

  • upon consulting with ChatGPT,

    That was a mistake. ChatGPT usually emits answers that sound good, but it is very bad at writing correct answers to technical questions. This is the worst possible result: you may be inclined to trust the answer because of its form, but to evaluate its correctness you need to know enough that you didn't need to ask ChatGPT in the first place.

    I was informed that there could be potential risks involved.

    Did ChatGPT put it in those terms? That would be misleading. It's not just risky to pass that pointer to free -- it is wrong.

    ChatGPT advised me to register a new function called 'freeJnaValue' within the C context and use that function to free the 'value' instead.

    And that is absurd. The name "freeJnaValue" has no special significance, and if it were ok to free the object provided by the callback, then it would be ok to do it directly in the function that received it from the callback. There is no particular advantage to interposing another function for the purpose.

    The JNA API docs say

    If the callback returns a String or String[], the returned memory will be valid until the returned object is GC'd.

    This tells you that the mapped C string returned to your callback's caller is managed by Java. You should not free it yourself at all.

    As a side note, because it is mapped to a String and Strings are immutable, you should not rely on being able to modify it. It would be better, then, to declare it on the C side to return const char * instead of just char *.