From 57d053a8fb6ed0893008ced1070c853c3ed78a77 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Wed, 14 Dec 2016 23:33:15 -0800 Subject: [PATCH] jni_util: Make JStringRef and JArrayRef null-safe. They return empty string and empty array (to avoid crashes) but also report an error with backtrace to stderr when called in that manner. --- include/support/jni_util.h | 87 +++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 34 deletions(-) diff --git a/include/support/jni_util.h b/include/support/jni_util.h index 5395aea31a..39ec6bfbb2 100644 --- a/include/support/jni_util.h +++ b/include/support/jni_util.h @@ -104,11 +104,16 @@ class JLocal { class JStringRef { public: JStringRef(JNIEnv *env, jstring str) { - jsize size = env->GetStringLength(str); - const jchar *chars = env->GetStringCritical(str, nullptr); - if (chars) { - llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str); - env->ReleaseStringCritical(str, chars); + if (str) { + jsize size = env->GetStringLength(str); + const jchar *chars = env->GetStringCritical(str, nullptr); + if (chars) { + llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str); + env->ReleaseStringCritical(str, chars); + } + } else { + llvm::errs() << "JStringRef was passed a null pointer at \n" + << GetJavaStackTrace(env); } } @@ -186,7 +191,7 @@ class JArrayRefBase : public JArrayRefInner, T> { JArrayRefBase(JNIEnv *env, jarray jarr) { this->m_env = env; this->m_jarr = jarr; - this->m_size = env->GetArrayLength(jarr); + this->m_size = jarr ? env->GetArrayLength(jarr) : 0; this->m_elements = nullptr; } @@ -200,34 +205,48 @@ class JArrayRefBase : public JArrayRefInner, T> { // Java array / DirectBuffer reference. -#define WPI_JNI_JARRAYREF(T, F) \ - class J##F##ArrayRef : public detail::JArrayRefBase { \ - public: \ - J##F##ArrayRef(JNIEnv *env, jobject bb, int len) \ - : detail::JArrayRefBase( \ - env, static_cast(env->GetDirectBufferAddress(bb)), len) {} \ - J##F##ArrayRef(JNIEnv *env, T##Array jarr) \ - : detail::JArrayRefBase(env, jarr) { \ - m_elements = env->Get##F##ArrayElements(jarr, nullptr); \ - } \ - ~J##F##ArrayRef() { \ - if (m_jarr && m_elements) \ - m_env->Release##F##ArrayElements(static_cast(m_jarr), \ - m_elements, JNI_ABORT); \ - } \ - }; \ - \ - class CriticalJ##F##ArrayRef : public detail::JArrayRefBase { \ - public: \ - CriticalJ##F##ArrayRef(JNIEnv *env, T##Array jarr) \ - : detail::JArrayRefBase(env, jarr) { \ - m_elements = \ - static_cast(env->GetPrimitiveArrayCritical(jarr, nullptr)); \ - } \ - ~CriticalJ##F##ArrayRef() { \ - if (m_jarr && m_elements) \ - m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \ - } \ +#define WPI_JNI_JARRAYREF(T, F) \ + class J##F##ArrayRef : public detail::JArrayRefBase { \ + public: \ + J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \ + : detail::JArrayRefBase( \ + env, \ + static_cast(bb ? env->GetDirectBufferAddress(bb) : nullptr), \ + len) { \ + if (!bb) \ + llvm::errs() << "JArrayRef was passed a null pointer at \n" \ + << GetJavaStackTrace(env); \ + } \ + J##F##ArrayRef(JNIEnv* env, T##Array jarr) \ + : detail::JArrayRefBase(env, jarr) { \ + if (jarr) \ + m_elements = env->Get##F##ArrayElements(jarr, nullptr); \ + else \ + llvm::errs() << "JArrayRef was passed a null pointer at \n" \ + << GetJavaStackTrace(env); \ + } \ + ~J##F##ArrayRef() { \ + if (m_jarr && m_elements) \ + m_env->Release##F##ArrayElements(static_cast(m_jarr), \ + m_elements, JNI_ABORT); \ + } \ + }; \ + \ + class CriticalJ##F##ArrayRef : public detail::JArrayRefBase { \ + public: \ + CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \ + : detail::JArrayRefBase(env, jarr) { \ + if (jarr) \ + m_elements = \ + static_cast(env->GetPrimitiveArrayCritical(jarr, nullptr)); \ + else \ + llvm::errs() << "JArrayRef was passed a null pointer at \n" \ + << GetJavaStackTrace(env); \ + } \ + ~CriticalJ##F##ArrayRef() { \ + if (m_jarr && m_elements) \ + m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \ + } \ }; WPI_JNI_JARRAYREF(jboolean, Boolean)