Skip to content

Commit 35fda7f

Browse files
committed
Fix JNI local reference table overflow when wrapping Java class with large method counts
1 parent 0622cee commit 35fda7f

File tree

5 files changed

+77
-120
lines changed

5 files changed

+77
-120
lines changed

platform/android/java_class_wrapper.cpp

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
4343
JNIEnv *env = get_jni_env();
4444
ERR_FAIL_NULL_V(env, false);
4545

46+
env->PushLocalFrame(p_argcount);
47+
4648
MethodInfo *method = nullptr;
4749
for (MethodInfo &E : M->value) {
4850
if (!p_instance && !E._static && !E._constructor) {
@@ -284,7 +286,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
284286
argv = (jvalue *)alloca(sizeof(jvalue) * method->param_types.size());
285287
}
286288

287-
List<jobject> to_free;
288289
for (int i = 0; i < method->param_types.size(); i++) {
289290
switch (method->param_types[i]) {
290291
case ARG_TYPE_VOID: {
@@ -323,7 +324,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
323324
val.z = (bool)(*p_args[i]);
324325
jobject obj = env->NewObjectA(bclass, ctor, &val);
325326
argv[i].l = obj;
326-
to_free.push_back(obj);
327327
} break;
328328
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_BYTE: {
329329
jclass bclass = jni_find_class(env, "java/lang/Byte");
@@ -332,7 +332,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
332332
val.b = (int)(*p_args[i]);
333333
jobject obj = env->NewObjectA(bclass, ctor, &val);
334334
argv[i].l = obj;
335-
to_free.push_back(obj);
336335
} break;
337336
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_CHAR: {
338337
jclass bclass = jni_find_class(env, "java/lang/Character");
@@ -341,7 +340,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
341340
val.c = (int)(*p_args[i]);
342341
jobject obj = env->NewObjectA(bclass, ctor, &val);
343342
argv[i].l = obj;
344-
to_free.push_back(obj);
345343
} break;
346344
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_SHORT: {
347345
jclass bclass = jni_find_class(env, "java/lang/Short");
@@ -350,7 +348,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
350348
val.s = (int)(*p_args[i]);
351349
jobject obj = env->NewObjectA(bclass, ctor, &val);
352350
argv[i].l = obj;
353-
to_free.push_back(obj);
354351
} break;
355352
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_INT: {
356353
jclass bclass = jni_find_class(env, "java/lang/Integer");
@@ -359,7 +356,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
359356
val.i = (int)(*p_args[i]);
360357
jobject obj = env->NewObjectA(bclass, ctor, &val);
361358
argv[i].l = obj;
362-
to_free.push_back(obj);
363359
} break;
364360
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_LONG: {
365361
jclass bclass = jni_find_class(env, "java/lang/Long");
@@ -368,7 +364,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
368364
val.j = (int64_t)(*p_args[i]);
369365
jobject obj = env->NewObjectA(bclass, ctor, &val);
370366
argv[i].l = obj;
371-
to_free.push_back(obj);
372367
} break;
373368
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_FLOAT: {
374369
jclass bclass = jni_find_class(env, "java/lang/Float");
@@ -377,7 +372,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
377372
val.f = (float)(*p_args[i]);
378373
jobject obj = env->NewObjectA(bclass, ctor, &val);
379374
argv[i].l = obj;
380-
to_free.push_back(obj);
381375
} break;
382376
case ARG_NUMBER_CLASS_BIT | ARG_TYPE_DOUBLE: {
383377
jclass bclass = jni_find_class(env, "java/lang/Double");
@@ -386,23 +380,20 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
386380
val.d = (double)(*p_args[i]);
387381
jobject obj = env->NewObjectA(bclass, ctor, &val);
388382
argv[i].l = obj;
389-
to_free.push_back(obj);
390383
} break;
391384
case ARG_TYPE_STRING:
392385
case ARG_TYPE_CHARSEQUENCE: {
393386
String s = *p_args[i];
394387
jstring jStr = env->NewStringUTF(s.utf8().get_data());
395388
argv[i].l = jStr;
396-
to_free.push_back(jStr);
397389
} break;
398390
case ARG_TYPE_CALLABLE: {
399391
jobject jcallable = callable_to_jcallable(env, *p_args[i]);
400392
argv[i].l = jcallable;
401-
to_free.push_back(jcallable);
402393
} break;
403394
case ARG_TYPE_CLASS: {
404395
if (p_args[i]->get_type() == Variant::DICTIONARY) {
405-
argv[i].l = _variant_to_jvalue(env, Variant::DICTIONARY, p_args[i]).obj;
396+
argv[i].l = _variant_to_jvalue(env, Variant::DICTIONARY, p_args[i]).l;
406397
} else {
407398
Ref<JavaObject> jo = *p_args[i];
408399
if (jo.is_valid()) {
@@ -420,8 +411,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
420411
env->SetBooleanArrayRegion(a, j, 1, &val);
421412
}
422413
argv[i].l = a;
423-
to_free.push_back(a);
424-
425414
} break;
426415
case ARG_ARRAY_BIT | ARG_TYPE_BYTE: {
427416
jbyteArray a = nullptr;
@@ -440,8 +429,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
440429
}
441430

442431
argv[i].l = a;
443-
to_free.push_back(a);
444-
445432
} break;
446433
case ARG_ARRAY_BIT | ARG_TYPE_CHAR: {
447434
jcharArray a = nullptr;
@@ -462,7 +449,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
462449
}
463450

464451
argv[i].l = a;
465-
to_free.push_back(a);
466452

467453
} break;
468454
case ARG_ARRAY_BIT | ARG_TYPE_SHORT: {
@@ -485,7 +471,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
485471
}
486472

487473
argv[i].l = a;
488-
to_free.push_back(a);
489474

490475
} break;
491476
case ARG_ARRAY_BIT | ARG_TYPE_INT: {
@@ -505,7 +490,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
505490
}
506491

507492
argv[i].l = a;
508-
to_free.push_back(a);
509493
} break;
510494
case ARG_ARRAY_BIT | ARG_TYPE_LONG: {
511495
jlongArray a = nullptr;
@@ -524,8 +508,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
524508
}
525509

526510
argv[i].l = a;
527-
to_free.push_back(a);
528-
529511
} break;
530512
case ARG_ARRAY_BIT | ARG_TYPE_FLOAT: {
531513
jfloatArray a = nullptr;
@@ -544,8 +526,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
544526
}
545527

546528
argv[i].l = a;
547-
to_free.push_back(a);
548-
549529
} break;
550530
case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE: {
551531
jdoubleArray a = nullptr;
@@ -564,8 +544,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
564544
}
565545

566546
argv[i].l = a;
567-
to_free.push_back(a);
568-
569547
} break;
570548
case ARG_ARRAY_BIT | ARG_TYPE_STRING:
571549
case ARG_ARRAY_BIT | ARG_TYPE_CHARSEQUENCE: {
@@ -578,7 +556,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
578556
String s = arr[j];
579557
jstring jStr = env->NewStringUTF(s.utf8().get_data());
580558
env->SetObjectArrayElement(a, j, jStr);
581-
to_free.push_back(jStr);
582559
}
583560
} else if (p_args[i]->get_type() == Variant::PACKED_STRING_ARRAY) {
584561
PackedStringArray arr = *p_args[i];
@@ -587,12 +564,10 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
587564
String s = arr[j];
588565
jstring jStr = env->NewStringUTF(s.utf8().get_data());
589566
env->SetObjectArrayElement(a, j, jStr);
590-
to_free.push_back(jStr);
591567
}
592568
}
593569

594570
argv[i].l = a;
595-
to_free.push_back(a);
596571
} break;
597572
case ARG_ARRAY_BIT | ARG_TYPE_CALLABLE: {
598573
Array arr = *p_args[i];
@@ -601,11 +576,9 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
601576
Variant callable = arr[j];
602577
jobject jcallable = callable_to_jcallable(env, callable);
603578
env->SetObjectArrayElement(jarr, j, jcallable);
604-
to_free.push_back(jcallable);
605579
}
606580

607581
argv[i].l = jarr;
608-
to_free.push_back(jarr);
609582
} break;
610583
case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
611584
String cn = method->param_sigs[i].operator String();
@@ -622,7 +595,6 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
622595
}
623596

624597
argv[i].l = jarr;
625-
to_free.push_back(jarr);
626598
}
627599
} break;
628600
}
@@ -720,30 +692,25 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
720692
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
721693
success = false;
722694
}
723-
env->DeleteLocalRef(obj);
724695
}
725696

726697
} break;
727698
}
728699

729-
for (jobject &E : to_free) {
730-
env->DeleteLocalRef(E);
731-
}
732-
733700
jobject exception = env->ExceptionOccurred();
734701
if (exception) {
735702
env->ExceptionClear();
736703

737704
jclass java_class = env->GetObjectClass(exception);
738705
Ref<JavaClass> java_class_wrapped = JavaClassWrapper::singleton->wrap_jclass(java_class);
739-
env->DeleteLocalRef(java_class);
740706

741707
JavaClassWrapper::singleton->exception.instantiate(java_class_wrapped, exception);
742-
env->DeleteLocalRef(exception);
743708
} else {
744709
JavaClassWrapper::singleton->exception.unref();
745710
}
746711

712+
env->PopLocalFrame(nullptr);
713+
747714
return success;
748715
}
749716

@@ -1522,22 +1489,16 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_non_p
15221489
java_class->_class = (jclass)env->NewGlobalRef(bclass);
15231490
class_cache[class_name_dots] = java_class;
15241491

1525-
LocalVector<jobject> methods_and_constructors;
15261492
int constructor_count = env->GetArrayLength(constructors);
15271493
int method_count = env->GetArrayLength(methods);
1528-
methods_and_constructors.resize(method_count + constructor_count);
1529-
for (int i = 0; i < constructor_count; i++) {
1530-
methods_and_constructors[i] = env->GetObjectArrayElement(constructors, i);
1531-
}
1532-
for (int i = 0; i < method_count; i++) {
1533-
methods_and_constructors[constructor_count + i] = env->GetObjectArrayElement(methods, i);
1534-
}
1535-
1536-
for (int i = 0; i < (int)methods_and_constructors.size(); i++) {
1537-
jobject obj = methods_and_constructors[i];
1538-
ERR_CONTINUE(!obj);
15391494

1495+
int methods_and_constructors_count = method_count + constructor_count;
1496+
for (int i = 0; i < methods_and_constructors_count; i++) {
15401497
bool is_constructor = i < constructor_count;
1498+
jobject obj = is_constructor
1499+
? env->GetObjectArrayElement(constructors, i)
1500+
: env->GetObjectArrayElement(methods, i - constructor_count);
1501+
ERR_CONTINUE(!obj);
15411502

15421503
String str_method;
15431504
if (is_constructor) {
@@ -1671,9 +1632,9 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_non_p
16711632
continue;
16721633
}
16731634

1674-
ERR_CONTINUE(!mi.method);
1675-
1676-
java_class->methods[str_method].push_back(mi);
1635+
if (mi.method) {
1636+
java_class->methods[str_method].push_back(mi);
1637+
}
16771638
}
16781639

16791640
env->DeleteLocalRef(obj);
@@ -1720,6 +1681,7 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_non_p
17201681
}
17211682

17221683
env->DeleteLocalRef(fields);
1684+
env->DeleteLocalRef(bclass);
17231685

17241686
return java_class;
17251687
}

platform/android/java_godot_lib_jni.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setEditorSetting(JNIE
514514
}
515515

516516
JNIEXPORT jobject JNICALL Java_org_godotengine_godot_GodotLib_getEditorProjectMetadata(JNIEnv *env, jclass clazz, jstring p_section, jstring p_key, jobject p_default_value) {
517-
jvalret result;
517+
jvalue result;
518518

519519
#ifdef TOOLS_ENABLED
520520
if (EditorSettings::get_singleton() != nullptr) {
@@ -528,7 +528,7 @@ JNIEXPORT jobject JNICALL Java_org_godotengine_godot_GodotLib_getEditorProjectMe
528528
WARN_PRINT("Access to the Editor Settings Project Metadata is only available on Editor builds");
529529
#endif
530530

531-
return result.obj;
531+
return result.l;
532532
}
533533

534534
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setEditorProjectMetadata(JNIEnv *env, jclass clazz, jstring p_section, jstring p_key, jobject p_data) {

0 commit comments

Comments
 (0)