Byte-array elements leak in `FromSchemaByteArray()`

Open Beginner friendly
#1,205 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
cpp, java
Domain
backend

Research direction

Start in dataset/src/main/cpp/jni_util.cc at FromSchemaByteArray() and inspect the GetByteArrayElements, ReadSchema, and ReleaseByteArrayElements flow. Verify the release also occurs when parsing fails, then exercise the malformed or incompatible schema path through createDataset(); done means the acquired JNI array elements are released on both success and error paths.

Written by the indexing model from the issue text.

Description

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

I found a possible JNI array leak in FromSchemaByteArray() when the serialized schema cannot be parsed.

File: dataset/src/main/cpp/jni_util.cc

Function: FromSchemaByteArray

Relevant code:

jbyte* schemaBytes_data =
    env->GetByteArrayElements(schemaBytes, nullptr);
auto serialized_schema = std::make_shared<arrow::Buffer>(
    reinterpret_cast<uint8_t*>(schemaBytes_data),
    schemaBytes_len);
arrow::io::BufferReader buf_reader(serialized_schema);

ARROW_ASSIGN_OR_RAISE(
    std::shared_ptr<arrow::Schema> schema,
    arrow::ipc::ReadSchema(&buf_reader, &in_memo))

env->ReleaseByteArrayElements(
    schemaBytes, schemaBytes_data, JNI_ABORT);
return schema;

GetByteArrayElements() returns a pointer that must be paired with
ReleaseByteArrayElements().

ARROW_ASSIGN_OR_RAISE returns immediately when ReadSchema() returns an
error. On that path, the release below the macro is skipped, so the acquired
array elements remain unreleased:

GetByteArrayElements succeeds
  -> ReadSchema returns an error
  -> ARROW_ASSIGN_OR_RAISE returns
  -> ReleaseByteArrayElements is skipped

The function is used by the public native createDataset() method:

schema = JniGetOrThrow(
    FromSchemaByteArray(env, schema_bytes));

Malformed, corrupted, or incompatible serialized schema bytes can therefore
reach this path. Repeated failed calls can retain copied array buffers or keep
Java arrays pinned, depending on the JVM implementation.

Suggested fix: release the elements before propagating the parse result, for
example:

auto schema_result =
    arrow::ipc::ReadSchema(&buf_reader, &in_memo);

env->ReleaseByteArrayElements(
    schemaBytes, schemaBytes_data, JNI_ABORT);

return schema_result;

An RAII guard for schemaBytes_data would also ensure release if additional
early returns are introduced later.

Dominant language
Java
Stars
95
Forks
154
Avg merge
2d 16h
Merged PRs (30d)
9

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from apache/arrow-java

All issues in apache/arrow-java

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.