Skip to content

[C Data] JNI release callback calls void PrivateData.close() with CallObjectMethod #1385

Open

Description

@niekbouman-rl

Describe the bug, including details regarding any error messages, version, and platform.

Disclaimer: Claude Opus 5 found this bug.

Describe the bug

In c/src/main/cpp/jni_wrapper.cc, the release callbacks of exported arrays/schemas
(release_exported) and of exported array streams call PrivateData.close() with
CallObjectMethod. That method is void (its ID is looked up with signature "()V"), and the JNI
specification requires the Call<type>Method matching the return type, i.e. CallVoidMethod:

kPrivateDataCloseMethod = GetMethodID(env, kPrivateDataClass, "close", "()V");
...
env->CallObjectMethod(private_data->j_private_data_, kPrivateDataCloseMethod);  // lines 173 and 298 at v19.0.0

HotSpot's -Xcheck:jni does not notice, but OpenJ9 (IBM Semeru) with -Xcheck:jni aborts the JVM
whenever an exported array, schema or stream is released, which happens whenever a native consumer
of the C Data Interface finishes with data exported from Java. We hit it with a Rust library that
imports batches exported with Data.exportVectorSchemaRoot and drops them.

To reproduce

import org.apache.arrow.c.ArrowArray;
import org.apache.arrow.c.ArrowSchema;
import org.apache.arrow.c.Data;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.vector.IntVector;

public class ReleaseRepro {
    public static void main(String[] args) {
        try (BufferAllocator allocator = new RootAllocator();
             IntVector v = new IntVector("x", allocator);
             ArrowArray array = ArrowArray.allocateNew(allocator);
             ArrowSchema schema = ArrowSchema.allocateNew(allocator)) {
            v.allocateNew(1);
            v.set(0, 1);
            v.setValueCount(1);
            Data.exportVector(allocator, v, null, array, schema);
            array.release();   // calls the exported struct's release callback
            schema.release();
        }
        System.out.println("done");
    }
}

Run on IBM Semeru 21.0.10+7 (OpenJ9 0.57.0) with arrow-c-data 19.0.0:

java -Xcheck:jni --add-opens=java.base/java.nio=ALL-UNNAMED -cp ... ReleaseRepro
JVMJNCK001I JNI check utility installed. Use -Xcheck:jni:help for usage
JVMJNCK046E JNI error in CallObjectMethod/CallObjectMethodV: Method has wrong return type ('V')
JVMJNCK077E Error detected in org/apache/arrow/c/jni/JniWrapper.releaseArray(J)V

JVMJNCK024E JNI error detected. Aborting.
JVMJNCK025I Use -Xcheck:jni:nonfatal to continue running when errors are detected.

Fatal error: JNI error

On HotSpot 21 the same program prints done.

Expected behavior

No JNI check error: both calls of close() in jni_wrapper.cc use CallVoidMethod. Present at
v19.0.0 and unchanged on main.

Component(s)

Java (arrow-c-data 19.0.0)

Activity

  1. hutiefang76 commented on Oct 24, 2026

    @hutiefang76
    Contributor

    I'll take a focused look at the two native release callbacks. I'll reproduce the return-type mismatch with OpenJ9's JNI checks and cover array, schema and stream release, including cleanup after a Java close exception. The patch will stay within the C Data release code and its tests.

    AI-generated coordination comment; investigation and validation assisted by Codex and DeepSeek.

  2. added this to the 20.0.0 milestone on Oct 24, 2026
  3. added a commit that references this issue on Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions