From b65b307a37b2332c1c9d498275427e8609048d3d Mon Sep 17 00:00:00 2001 From: Nathanael Anderson Date: Thu, 21 May 2015 00:08:16 -0500 Subject: [PATCH 1/3] JNI apparently caches stuff in a local reference table; it can only supports 512 items. Doing some work in a loop that references a several variables can cause this table to exceed and then the app will crash with the following error: JNI ERROR (app bug): local reference table overflow (max=512) JNI local reference table (0xb9987968) dump: Failed adding to JNI local ref table (has 512 entries) --- src/jni/ArgConverter.cpp | 4 +++- src/jni/ArrayElementAccessor.cpp | 2 ++ src/jni/ExceptionUtil.cpp | 2 ++ src/jni/FieldAccessor.cpp | 1 + src/jni/JEnv.cpp | 3 +++ src/jni/JsArgConverter.cpp | 1 + src/jni/NativeScriptRuntime.cpp | 2 ++ src/jni/com_tns_Platform.cpp | 1 + 8 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/jni/ArgConverter.cpp b/src/jni/ArgConverter.cpp index 3dd823411..a6fa8ddcf 100644 --- a/src/jni/ArgConverter.cpp +++ b/src/jni/ArgConverter.cpp @@ -238,6 +238,7 @@ std::string ArgConverter::jstringToString(jstring value) const char* chars = env.GetStringUTFChars(value, &f); string s(chars); env.ReleaseStringUTFChars(value, chars); + env.DeleteLocalRef(value); return s; } @@ -251,6 +252,7 @@ Handle ArgConverter::jcharToV8String(jchar value) const char* resP = env.GetStringUTFChars(str, &bol); auto v8String = ConvertToV8String(resP, 1); env.ReleaseStringUTFChars(str, resP); + env.DeleteLocalRef(str); return v8String; } @@ -268,7 +270,7 @@ Local ArgConverter::jstringToV8String(jstring value) jbyte *data = env.GetByteArrayElements(arr, nullptr); auto v8String = ConvertToV8String((const char *)data, length); env.ReleaseByteArrayElements(arr, data, JNI_ABORT); - + env.DeleteLocalRef(arr); return v8String; } diff --git a/src/jni/ArrayElementAccessor.cpp b/src/jni/ArrayElementAccessor.cpp index 3edb67873..43b1ef1b3 100644 --- a/src/jni/ArrayElementAccessor.cpp +++ b/src/jni/ArrayElementAccessor.cpp @@ -56,6 +56,7 @@ Handle ArrayElementAccessor::GetArrayElement(const Handle& array, const char* singleChar = env.GetStringUTFChars(s, &isCopy); value = CheckForArrayAccessException(env, elementSignature, singleChar); env.ReleaseStringUTFChars(s, singleChar); + env.DeleteLocalRef(s); } else if (elementSignature == "S") { @@ -133,6 +134,7 @@ void ArrayElementAccessor::SetArrayElement(const Handle& array, uint32_t const char* singleChar = env.GetStringUTFChars(s, &isCopy); jchar charElementValue = *singleChar; env.ReleaseStringUTFChars(s, singleChar); + env.DeleteLocalRef(s); jcharArray charArr = reinterpret_cast(arr); env.SetCharArrayRegion(charArr, index, 1, &charElementValue); } diff --git a/src/jni/ExceptionUtil.cpp b/src/jni/ExceptionUtil.cpp index fb9f863ff..183c91dab 100644 --- a/src/jni/ExceptionUtil.cpp +++ b/src/jni/ExceptionUtil.cpp @@ -89,6 +89,7 @@ void ExceptionUtil::GetExceptionMessage(JEnv& env, jthrowable exception, string& } env.ReleaseStringUTFChars(msg, msgStr); + env.DeleteLocalRef(msg); } for (jsize i = 0; i < framesLength; i++) @@ -102,6 +103,7 @@ void ExceptionUtil::GetExceptionMessage(JEnv& env, jthrowable exception, string& errMsg.append(msgStr); env.ReleaseStringUTFChars(msg, msgStr); + env.DeleteLocalRef(msg); } if (nullptr != (jobjectArray) frames) diff --git a/src/jni/FieldAccessor.cpp b/src/jni/FieldAccessor.cpp index 9b80a9e24..d5255bdba 100644 --- a/src/jni/FieldAccessor.cpp +++ b/src/jni/FieldAccessor.cpp @@ -110,6 +110,7 @@ Handle FieldAccessor::GetJavaField(const Handle& target, FieldCal jboolean bol = true; const char* resP = env.GetStringUTFChars(str, &bol); env.ReleaseStringUTFChars(str, resP); + env.DeleteLocalRef(str); fieldResult = handleScope.Escape(ConvertToV8String(resP, 1)); break; } diff --git a/src/jni/JEnv.cpp b/src/jni/JEnv.cpp index 16eac1a60..d729e4c25 100644 --- a/src/jni/JEnv.cpp +++ b/src/jni/JEnv.cpp @@ -393,6 +393,9 @@ void JEnv::ReleaseStringUTFChars(jstring str, const char* utf) m_env->ReleaseStringUTFChars(str, utf); } +void JEnv::DeleteLocalRef(jstring str) { + m_env->DeleteLocalRef(str); +} jint JEnv::Throw(jthrowable obj) { diff --git a/src/jni/JsArgConverter.cpp b/src/jni/JsArgConverter.cpp index 8b952174f..101405f1f 100644 --- a/src/jni/JsArgConverter.cpp +++ b/src/jni/JsArgConverter.cpp @@ -417,6 +417,7 @@ bool JsArgConverter::ConvertJavaScriptArray(JEnv& env, const Handle& jsAr const char* singleChar = env.GetStringUTFChars(s, nullptr); jchar value = *singleChar; env.ReleaseStringUTFChars(s, singleChar); + env.DeleteLocalRef(s); env.SetCharArrayRegion((jcharArray)arr, i, 1, &value); } break; diff --git a/src/jni/NativeScriptRuntime.cpp b/src/jni/NativeScriptRuntime.cpp index 009cd5389..df7974008 100644 --- a/src/jni/NativeScriptRuntime.cpp +++ b/src/jni/NativeScriptRuntime.cpp @@ -312,6 +312,7 @@ void NativeScriptRuntime::CallJavaMethod(const Handle& caller, const str jboolean bol = true; const char* resP = env.GetStringUTFChars(str, &bol); env.ReleaseStringUTFChars(str, resP); + env.DeleteLocalRef(str); args.GetReturnValue().Set(ConvertToV8String(resP, 1)); break; } @@ -858,6 +859,7 @@ vector NativeScriptRuntime::GetTypeMetadata(const string& name, int inde const char *pc = env.GetStringUTFChars(s, nullptr); result.push_back(string(pc)); env.ReleaseStringUTFChars(s, pc); + env.DeleteLocalRef(s); } return result; diff --git a/src/jni/com_tns_Platform.cpp b/src/jni/com_tns_Platform.cpp index 71cb20134..63a77c609 100644 --- a/src/jni/com_tns_Platform.cpp +++ b/src/jni/com_tns_Platform.cpp @@ -203,6 +203,7 @@ extern "C" void Java_com_tns_Platform_runNativeScript(JNIEnv *_env, jobject obj, auto cmd = ConvertToV8String(code); env.ReleaseStringUTFChars(appCode, code); + env.DeleteLocalRef(appCode); DEBUG_WRITE("Compiling script"); From 1711fe6b9d4cce62d2439a57a3190ce925b93512 Mon Sep 17 00:00:00 2001 From: Nathanael Anderson Date: Sat, 23 May 2015 17:12:27 -0500 Subject: [PATCH 2/3] Fixed to have deleteRef properly defined --- src/jni/JEnv.cpp | 4 ++-- src/jni/JEnv.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jni/JEnv.cpp b/src/jni/JEnv.cpp index d729e4c25..89551d2ba 100644 --- a/src/jni/JEnv.cpp +++ b/src/jni/JEnv.cpp @@ -393,8 +393,8 @@ void JEnv::ReleaseStringUTFChars(jstring str, const char* utf) m_env->ReleaseStringUTFChars(str, utf); } -void JEnv::DeleteLocalRef(jstring str) { - m_env->DeleteLocalRef(str); +void JEnv::DeleteLocalRef(jobject obj) { + m_env->DeleteLocalRef(obj); } jint JEnv::Throw(jthrowable obj) diff --git a/src/jni/JEnv.h b/src/jni/JEnv.h index 359a09bc9..77ec0415f 100644 --- a/src/jni/JEnv.h +++ b/src/jni/JEnv.h @@ -119,6 +119,7 @@ namespace tns const char* GetStringUTFChars(jstring str, jboolean* isCopy); void ReleaseStringUTFChars(jstring str, const char* utf); + void DeleteLocalRef(jobject obj); jint Throw(jthrowable obj); jboolean ExceptionCheck(); From dd65560fb711888bbd697ec2c0a690e7f11f3757 Mon Sep 17 00:00:00 2001 From: Nathanael Anderson Date: Sat, 23 May 2015 20:16:04 -0500 Subject: [PATCH 3/3] Eliminate my added copy of DeleteLocalRef --- src/jni/JEnv.cpp | 4 ---- src/jni/JEnv.h | 1 - 2 files changed, 5 deletions(-) diff --git a/src/jni/JEnv.cpp b/src/jni/JEnv.cpp index 89551d2ba..90d2342db 100644 --- a/src/jni/JEnv.cpp +++ b/src/jni/JEnv.cpp @@ -393,10 +393,6 @@ void JEnv::ReleaseStringUTFChars(jstring str, const char* utf) m_env->ReleaseStringUTFChars(str, utf); } -void JEnv::DeleteLocalRef(jobject obj) { - m_env->DeleteLocalRef(obj); -} - jint JEnv::Throw(jthrowable obj) { return m_env->Throw(obj); diff --git a/src/jni/JEnv.h b/src/jni/JEnv.h index 77ec0415f..359a09bc9 100644 --- a/src/jni/JEnv.h +++ b/src/jni/JEnv.h @@ -119,7 +119,6 @@ namespace tns const char* GetStringUTFChars(jstring str, jboolean* isCopy); void ReleaseStringUTFChars(jstring str, const char* utf); - void DeleteLocalRef(jobject obj); jint Throw(jthrowable obj); jboolean ExceptionCheck();