JNI local-reference accumulation in the string array helpers
- Langage dominant
- Java
- Étoiles
- 94
- Forks
- 152
- Merge moyen
- 3 j 16 h
- PR mergées (30 j)
- 11
Description
### 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()`.
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Commencez par lire ToStringVector dans dataset/src/main/cpp/jni_util.cc ainsi que ToStringMap et LoadNamedTables dans dataset/src/main/cpp/jni_wrapper.cc, en vous concentrant sur chaque appel à GetObjectArrayElement. Assurez-vous que chaque référence locale acquise est supprimée sur les chemins normaux et les chemins JniThrow() ; c’est terminé lorsqu’aucune référence de l’itération courante ne reste abandonnée.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- cpp, java
- Domaine
- backend
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Calme
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 75/100