Local reference accumulation in `btMultiSphereShape` `Vector3[]` conversion
Describe the bug
I found a possible JNI local reference leak in the btMultiSphereShape Vector3[] conversion helper. The helper calls GetObjectArrayElement() for each Java Vector3, but the returned local references are not deleted.
File: extensions/gdx-bullet/jni/swig/collision/btMultiSphereShape.i
Generated file:
extensions/gdx-bullet/jni/swig-src/collision/collision_wrap.cpp
Function: Vector3ArrayToBtVector3Array
Relevant code:
btVector3* Vector3ArrayToBtVector3Array(JNIEnv * jenv, jobjectArray source) {
static jfieldID xField = NULL, yField = NULL, zField = NULL;
jint len = jenv->GetArrayLength(source);
if (len <= 0)
return NULL;
btVector3* result = new btVector3[len];
if (xField == NULL) {
jobject vec = jenv->GetObjectArrayElement(source, 0);
jclass sc = jenv->GetObjectClass(vec);
xField = jenv->GetFieldID(sc, "x", "F");
yField = jenv->GetFieldID(sc, "y", "F");
zField = jenv->GetFieldID(sc, "z", "F");
jenv->DeleteLocalRef(sc);
}
for (int i = 0; i < len; i++) {
jobject vec = jenv->GetObjectArrayElement(source, i);
result[i].setValue(jenv->GetFloatField(vec, xField), jenv->GetFloatField(vec, yField), jenv->GetFloatField(vec, zField));
}
return result;
}GetObjectArrayElement() returns a JNI local reference. The loop creates one
local reference per input element and keeps all of them live until the native
method returns. With a large enough Vector3[], this can overflow the JNI local
reference table during one call.
There is also a smaller one-time leak in the field-cache initialization path:
the source[0] object local reference is used to get the class, but only the
class reference sc is deleted.
This helper is used by the SWIG typemap for btVector3*:
%typemap(in, fragment="gdxBulletHelpersVector3Array", noblock=1) btVector3* {
static jfieldID xField = NULL, yField = NULL, zField = NULL;
$1 = Vector3ArrayToBtVector3Array(jenv, $input);
gdxAutoDeleteBtVector3Array auto_delete($1);
}The Java-facing constructor reaches this path:
public btMultiSphereShape (Vector3[] positions, float[] radi, int numSpheres) {
this(CollisionJNI.new_btMultiSphereShape(positions, radi, numSpheres), true);
}Suggested fix: delete each vec local reference after its fields are copied,
and also delete the vec local reference used while initializing xField,
yField, and zField. The fix should be made in
btMultiSphereShape.i, then the generated SWIG wrapper should be regenerated.
For example:
jobject vec = jenv->GetObjectArrayElement(source, i);
result[i].setValue(jenv->GetFloatField(vec, xField), jenv->GetFloatField(vec, yField), jenv->GetFloatField(vec, zField));
jenv->DeleteLocalRef(vec);Reproduction
No response
version
No response
Stack trace
Affected platforms
- Android
- iOS
- HTML/GWT
- Windows
- Linux
- macOS
Source: libgdx/libgdx