apache / apache/arrow-java

JNI local-reference accumulation in the string array helpers

未關閉
#1,256 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
Type: bug
主要語言
Java
星號
94
分支
152
平均合併
3 天 16 小時
30 天內合併 PR
11

描述

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

There is a JNI local-reference issue in the dataset helpers that convert Java `String[]` arrays into C++ containers. They get each element with `GetObjectArrayElement()` and convert it, but never delete the resulting local reference.

Files:

- `dataset/src/main/cpp/jni_util.cc`
- `dataset/src/main/cpp/jni_wrapper.cc`

Functions:

- `ToStringVector` (`jni_util.cc`)
- `ToStringMap`, `LoadNamedTables` (`jni_wrapper.cc`)

Relevant code in `ToStringVector()`:

```cpp
std::vector ToStringVector(JNIEnv* env, jobjectArray& str_array) {
int length = env->GetArrayLength(str_array);
std::vector vector;
for (int i = 0; i < length; i++) {
auto string = reinterpret_cast(env->GetObjectArrayElement(str_array, i));
vector.push_back(JStringToCString(env, string));
}
return vector;
}
```

`JStringToCString()` does correctly release the native UTF chars it acquires:

```cpp
const char* chars = env->GetStringUTFChars(string, nullptr);
std::string ret(chars);
env->ReleaseStringUTFChars(string, chars);
return ret;
```

but that release only matches `GetStringUTFChars()`. It does not delete the `jstring` local reference that `GetObjectArrayElement()` returned, so one reference remains live per element until the native method returns.

`ToStringMap()` has the same pattern with two references per iteration:

```cpp
for (int i = 0; i < length; i += 2) {
auto key = reinterpret_cast(env->GetObjectArrayElement(str_array, i));
auto value = reinterpret_cast(env->GetObjectArrayElement(str_array, i + 1));
map[JStringToCString(env, key)] = JStringToCString(env, value);
}
```

`LoadNamedTables()` also takes two per iteration, and has three `JniThrow()` exits inside the loop body — the odd-length check and the two `std::stol` failure handlers — so on those paths the references acquired in the current iteration are abandoned mid-loop.

These are local references, so they are reclaimed when the native method returns, and the inputs are option maps, partition columns, and named-table lists — typically tens of entries. There is no observable leak or reachable failure here; the reference count is simply higher than necessary for the duration of the call.

Suggested fix:

```cpp
auto string = reinterpret_cast(env->GetObjectArrayElement(str_array, i));
vector.push_back(JStringToCString(env, string));
env->DeleteLocalRef(string);
```

For the key/value loops, delete both `key` and `value`, including on the `JniThrow()` paths in `LoadNamedTables()`.

貢獻指南

開啟貢獻指南

研究方向

先閱讀 dataset/src/main/cpp/jni_util.cc 中的 ToStringVector,以及 dataset/src/main/cpp/jni_wrapper.cc 中的 ToStringMap 和 LoadNamedTables,著重檢查每個 GetObjectArrayElement 呼叫。確保每個取得的區域參照都在正常路徑和 JniThrow() 路徑上被刪除;完成的標準是目前迭代不再有任何被遺棄的參照。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
cpp, java
領域
backend
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
冷清
描述清晰度
描述清楚
新手友好度
75/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。