summaryrefslogtreecommitdiffstats
path: root/runtime/jni_internal_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/jni_internal_test.cc')
-rw-r--r--runtime/jni_internal_test.cc975
1 files changed, 656 insertions, 319 deletions
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index da3080f218..844d14a063 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -17,6 +17,7 @@
#include "jni_internal.h"
#include "common_compiler_test.h"
+#include "java_vm_ext.h"
#include "mirror/art_method-inl.h"
#include "mirror/string-inl.h"
#include "scoped_thread_state_change.h"
@@ -53,24 +54,15 @@ class JniInternalTest : public CommonCompilerTest {
}
void ExpectException(jclass exception_class) {
- EXPECT_TRUE(env_->ExceptionCheck());
+ ScopedObjectAccess soa(env_);
+ EXPECT_TRUE(env_->ExceptionCheck())
+ << PrettyDescriptor(soa.Decode<mirror::Class*>(exception_class));
jthrowable exception = env_->ExceptionOccurred();
EXPECT_NE(nullptr, exception);
env_->ExceptionClear();
EXPECT_TRUE(env_->IsInstanceOf(exception, exception_class));
}
- void ExpectClassFound(const char* name) {
- EXPECT_NE(env_->FindClass(name), nullptr) << name;
- EXPECT_FALSE(env_->ExceptionCheck()) << name;
- }
-
- void ExpectClassNotFound(const char* name) {
- EXPECT_EQ(env_->FindClass(name), nullptr) << name;
- EXPECT_TRUE(env_->ExceptionCheck()) << name;
- env_->ExceptionClear();
- }
-
void CleanUpJniEnv() {
if (aioobe_ != nullptr) {
env_->DeleteGlobalRef(aioobe_);
@@ -98,6 +90,510 @@ class JniInternalTest : public CommonCompilerTest {
return soa.AddLocalReference<jclass>(c);
}
+ void ExpectClassFound(const char* name) {
+ EXPECT_NE(env_->FindClass(name), nullptr) << name;
+ EXPECT_FALSE(env_->ExceptionCheck()) << name;
+ }
+
+ void ExpectClassNotFound(const char* name, bool check_jni, const char* check_jni_msg,
+ CheckJniAbortCatcher* abort_catcher) {
+ EXPECT_EQ(env_->FindClass(name), nullptr) << name;
+ if (!check_jni || check_jni_msg == nullptr) {
+ EXPECT_TRUE(env_->ExceptionCheck()) << name;
+ env_->ExceptionClear();
+ } else {
+ abort_catcher->Check(check_jni_msg);
+ }
+ }
+
+ void FindClassTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ // Null argument is always an abort.
+ env_->FindClass(nullptr);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "name == null");
+
+ // Reference types...
+ ExpectClassFound("java/lang/String");
+ // ...for arrays too, where you must include "L;".
+ ExpectClassFound("[Ljava/lang/String;");
+ // Primitive arrays are okay too, if the primitive type is valid.
+ ExpectClassFound("[C");
+
+ // But primitive types aren't allowed...
+ ExpectClassNotFound("C", check_jni, nullptr, &check_jni_abort_catcher);
+ ExpectClassNotFound("V", check_jni, nullptr, &check_jni_abort_catcher);
+ ExpectClassNotFound("K", check_jni, nullptr, &check_jni_abort_catcher);
+
+ if (check_jni) {
+ // Check JNI will reject invalid class names as aborts but without pending exceptions.
+ EXPECT_EQ(env_->FindClass("java.lang.String"), nullptr);
+ EXPECT_FALSE(env_->ExceptionCheck());
+ check_jni_abort_catcher.Check("illegal class name 'java.lang.String'");
+
+ EXPECT_EQ(env_->FindClass("[Ljava.lang.String;"), nullptr);
+ EXPECT_FALSE(env_->ExceptionCheck());
+ check_jni_abort_catcher.Check("illegal class name '[Ljava.lang.String;'");
+ } else {
+ // Without check JNI we're tolerant and replace '.' with '/'.
+ ExpectClassFound("java.lang.String");
+ ExpectClassFound("[Ljava.lang.String;");
+ }
+
+ ExpectClassNotFound("Ljava.lang.String;", check_jni, "illegal class name 'Ljava.lang.String;'",
+ &check_jni_abort_catcher);
+ ExpectClassNotFound("[java.lang.String", check_jni, "illegal class name '[java.lang.String'",
+ &check_jni_abort_catcher);
+
+ // You can't include the "L;" in a JNI class descriptor.
+ ExpectClassNotFound("Ljava/lang/String;", check_jni, "illegal class name 'Ljava/lang/String;'",
+ &check_jni_abort_catcher);
+
+ // But you must include it for an array of any reference type.
+ ExpectClassNotFound("[java/lang/String", check_jni, "illegal class name '[java/lang/String'",
+ &check_jni_abort_catcher);
+
+ ExpectClassNotFound("[K", check_jni, "illegal class name '[K'", &check_jni_abort_catcher);
+
+ // Void arrays aren't allowed.
+ ExpectClassNotFound("[V", check_jni, "illegal class name '[V'", &check_jni_abort_catcher);
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetFieldIdBadArgumentTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_NE(c, nullptr);
+
+ jfieldID fid = env_->GetFieldID(nullptr, "count", "I");
+ EXPECT_EQ(nullptr, fid);
+ check_jni_abort_catcher.Check(check_jni ? "GetFieldID received NULL jclass"
+ : "java_class == null");
+ fid = env_->GetFieldID(c, nullptr, "I");
+ EXPECT_EQ(nullptr, fid);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "name == null");
+ fid = env_->GetFieldID(c, "count", nullptr);
+ EXPECT_EQ(nullptr, fid);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "sig == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetStaticFieldIdBadArgumentTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_NE(c, nullptr);
+
+ jfieldID fid = env_->GetStaticFieldID(nullptr, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ EXPECT_EQ(nullptr, fid);
+ check_jni_abort_catcher.Check(check_jni ? "GetStaticFieldID received NULL jclass"
+ : "java_class == null");
+ fid = env_->GetStaticFieldID(c, nullptr, "Ljava/util/Comparator;");
+ EXPECT_EQ(nullptr, fid);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "name == null");
+ fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", nullptr);
+ EXPECT_EQ(nullptr, fid);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "sig == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetMethodIdBadArgumentTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ jmethodID method = env_->GetMethodID(nullptr, "<init>", "(Ljava/lang/String;)V");
+ EXPECT_EQ(nullptr, method);
+ check_jni_abort_catcher.Check(check_jni ? "GetMethodID received NULL jclass"
+ : "java_class == null");
+ jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
+ ASSERT_TRUE(jlnsme != nullptr);
+ method = env_->GetMethodID(jlnsme, nullptr, "(Ljava/lang/String;)V");
+ EXPECT_EQ(nullptr, method);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "name == null");
+ method = env_->GetMethodID(jlnsme, "<init>", nullptr);
+ EXPECT_EQ(nullptr, method);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "sig == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetStaticMethodIdBadArgumentTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ jmethodID method = env_->GetStaticMethodID(nullptr, "valueOf", "(I)Ljava/lang/String;");
+ EXPECT_EQ(nullptr, method);
+ check_jni_abort_catcher.Check(check_jni ? "GetStaticMethodID received NULL jclass"
+ : "java_class == null");
+ jclass jlstring = env_->FindClass("java/lang/String");
+ method = env_->GetStaticMethodID(jlstring, nullptr, "(I)Ljava/lang/String;");
+ EXPECT_EQ(nullptr, method);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "name == null");
+ method = env_->GetStaticMethodID(jlstring, "valueOf", nullptr);
+ EXPECT_EQ(nullptr, method);
+ check_jni_abort_catcher.Check(check_jni ? "non-nullable const char* was NULL"
+ : "sig == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetFromReflectedField_ToReflectedFieldBadArgumentTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_NE(c, nullptr);
+ jfieldID fid = env_->GetFieldID(c, "count", "I");
+ ASSERT_NE(fid, nullptr);
+
+ // Check class argument for null argument, not checked in non-check JNI.
+ jobject field = env_->ToReflectedField(nullptr, fid, JNI_FALSE);
+ if (check_jni) {
+ EXPECT_EQ(field, nullptr);
+ check_jni_abort_catcher.Check("ToReflectedField received NULL jclass");
+ } else {
+ EXPECT_NE(field, nullptr);
+ }
+
+ field = env_->ToReflectedField(c, nullptr, JNI_FALSE);
+ EXPECT_EQ(field, nullptr);
+ check_jni_abort_catcher.Check(check_jni ? "jfieldID was NULL"
+ : "fid == null");
+
+ fid = env_->FromReflectedField(nullptr);
+ ASSERT_EQ(fid, nullptr);
+ check_jni_abort_catcher.Check(check_jni ? "expected non-null java.lang.reflect.Field"
+ : "jlr_field == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetFromReflectedMethod_ToReflectedMethodBadArgumentTest(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_NE(c, nullptr);
+ jmethodID mid = env_->GetMethodID(c, "<init>", "()V");
+ ASSERT_NE(mid, nullptr);
+
+ // Check class argument for null argument, not checked in non-check JNI.
+ jobject method = env_->ToReflectedMethod(nullptr, mid, JNI_FALSE);
+ if (check_jni) {
+ EXPECT_EQ(method, nullptr);
+ check_jni_abort_catcher.Check("ToReflectedMethod received NULL jclass");
+ } else {
+ EXPECT_NE(method, nullptr);
+ }
+
+ method = env_->ToReflectedMethod(c, nullptr, JNI_FALSE);
+ EXPECT_EQ(method, nullptr);
+ check_jni_abort_catcher.Check(check_jni ? "jmethodID was NULL"
+ : "mid == null");
+ mid = env_->FromReflectedMethod(method);
+ ASSERT_EQ(mid, nullptr);
+ check_jni_abort_catcher.Check(check_jni ? "expected non-null method" : "jlr_method == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void RegisterAndUnregisterNativesBadArguments(bool check_jni,
+ CheckJniAbortCatcher* check_jni_abort_catcher) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ // Passing a class of null is a failure.
+ {
+ JNINativeMethod methods[] = { };
+ EXPECT_EQ(env_->RegisterNatives(nullptr, methods, 0), JNI_ERR);
+ check_jni_abort_catcher->Check(check_jni ? "RegisterNatives received NULL jclass"
+ : "java_class == null");
+ }
+
+ // Passing methods as null is a failure.
+ jclass jlobject = env_->FindClass("java/lang/Object");
+ EXPECT_EQ(env_->RegisterNatives(jlobject, nullptr, 1), JNI_ERR);
+ check_jni_abort_catcher->Check("methods == null");
+
+ // Unregisters null is a failure.
+ EXPECT_EQ(env_->UnregisterNatives(nullptr), JNI_ERR);
+ check_jni_abort_catcher->Check(check_jni ? "UnregisterNatives received NULL jclass"
+ : "java_class == null");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+
+ void GetPrimitiveArrayElementsOfWrongType(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher jni_abort_catcher;
+
+ jbooleanArray array = env_->NewBooleanArray(10);
+ jboolean is_copy;
+ EXPECT_EQ(env_->GetByteArrayElements(reinterpret_cast<jbyteArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected byte[]"
+ : "attempt to get byte primitive array elements with an object of type boolean[]");
+ EXPECT_EQ(env_->GetShortArrayElements(reinterpret_cast<jshortArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected short[]"
+ : "attempt to get short primitive array elements with an object of type boolean[]");
+ EXPECT_EQ(env_->GetCharArrayElements(reinterpret_cast<jcharArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected char[]"
+ : "attempt to get char primitive array elements with an object of type boolean[]");
+ EXPECT_EQ(env_->GetIntArrayElements(reinterpret_cast<jintArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected int[]"
+ : "attempt to get int primitive array elements with an object of type boolean[]");
+ EXPECT_EQ(env_->GetLongArrayElements(reinterpret_cast<jlongArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected long[]"
+ : "attempt to get long primitive array elements with an object of type boolean[]");
+ EXPECT_EQ(env_->GetFloatArrayElements(reinterpret_cast<jfloatArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected float[]"
+ : "attempt to get float primitive array elements with an object of type boolean[]");
+ EXPECT_EQ(env_->GetDoubleArrayElements(reinterpret_cast<jdoubleArray>(array), &is_copy), nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected double[]"
+ : "attempt to get double primitive array elements with an object of type boolean[]");
+ jbyteArray array2 = env_->NewByteArray(10);
+ EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), &is_copy),
+ nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type byte[] expected boolean[]"
+ : "attempt to get boolean primitive array elements with an object of type byte[]");
+ jobject object = env_->NewStringUTF("Test String");
+ EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), &is_copy),
+ nullptr);
+ jni_abort_catcher.Check(
+ check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "attempt to get boolean primitive array elements with an object of type java.lang.String");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void ReleasePrimitiveArrayElementsOfWrongType(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher jni_abort_catcher;
+
+ jbooleanArray array = env_->NewBooleanArray(10);
+ ASSERT_TRUE(array != nullptr);
+ jboolean is_copy;
+ jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
+ ASSERT_TRUE(elements != nullptr);
+ env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
+ reinterpret_cast<jbyte*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected byte[]"
+ : "attempt to release byte primitive array elements with an object of type boolean[]");
+ env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
+ reinterpret_cast<jshort*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected short[]"
+ : "attempt to release short primitive array elements with an object of type boolean[]");
+ env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
+ reinterpret_cast<jchar*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected char[]"
+ : "attempt to release char primitive array elements with an object of type boolean[]");
+ env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
+ reinterpret_cast<jint*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected int[]"
+ : "attempt to release int primitive array elements with an object of type boolean[]");
+ env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
+ reinterpret_cast<jlong*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected long[]"
+ : "attempt to release long primitive array elements with an object of type boolean[]");
+ env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
+ reinterpret_cast<jfloat*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected float[]"
+ : "attempt to release float primitive array elements with an object of type boolean[]");
+ env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
+ reinterpret_cast<jdouble*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected double[]"
+ : "attempt to release double primitive array elements with an object of type boolean[]");
+ jbyteArray array2 = env_->NewByteArray(10);
+ env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), elements, 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type byte[] expected boolean[]"
+ : "attempt to release boolean primitive array elements with an object of type byte[]");
+ jobject object = env_->NewStringUTF("Test String");
+ env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
+ jni_abort_catcher.Check(
+ check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "attempt to release boolean primitive array elements with an object of type "
+ "java.lang.String");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetReleasePrimitiveArrayCriticalOfWrongType(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher jni_abort_catcher;
+
+ jobject object = env_->NewStringUTF("Test String");
+ jboolean is_copy;
+ void* elements = env_->GetPrimitiveArrayCritical(reinterpret_cast<jarray>(object), &is_copy);
+ jni_abort_catcher.Check(check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "expected primitive array, given java.lang.String");
+ env_->ReleasePrimitiveArrayCritical(reinterpret_cast<jarray>(object), elements, 0);
+ jni_abort_catcher.Check(check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "expected primitive array, given java.lang.String");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void GetPrimitiveArrayRegionElementsOfWrongType(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher jni_abort_catcher;
+ constexpr size_t kLength = 10;
+ jbooleanArray array = env_->NewBooleanArray(kLength);
+ ASSERT_TRUE(array != nullptr);
+ jboolean elements[kLength];
+ env_->GetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
+ reinterpret_cast<jbyte*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected byte[]"
+ : "attempt to get region of byte primitive array elements with an object of type boolean[]");
+ env_->GetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
+ reinterpret_cast<jshort*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected short[]"
+ : "attempt to get region of short primitive array elements with an object of type boolean[]");
+ env_->GetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
+ reinterpret_cast<jchar*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected char[]"
+ : "attempt to get region of char primitive array elements with an object of type boolean[]");
+ env_->GetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
+ reinterpret_cast<jint*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected int[]"
+ : "attempt to get region of int primitive array elements with an object of type boolean[]");
+ env_->GetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
+ reinterpret_cast<jlong*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected long[]"
+ : "attempt to get region of long primitive array elements with an object of type boolean[]");
+ env_->GetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
+ reinterpret_cast<jfloat*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected float[]"
+ : "attempt to get region of float primitive array elements with an object of type boolean[]");
+ env_->GetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
+ reinterpret_cast<jdouble*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected double[]"
+ : "attempt to get region of double primitive array elements with an object of type boolean[]");
+ jbyteArray array2 = env_->NewByteArray(10);
+ env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
+ reinterpret_cast<jboolean*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type byte[] expected boolean[]"
+ : "attempt to get region of boolean primitive array elements with an object of type byte[]");
+ jobject object = env_->NewStringUTF("Test String");
+ env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
+ reinterpret_cast<jboolean*>(elements));
+ jni_abort_catcher.Check(check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "attempt to get region of boolean primitive array elements with an object of type "
+ "java.lang.String");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void SetPrimitiveArrayRegionElementsOfWrongType(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher jni_abort_catcher;
+ constexpr size_t kLength = 10;
+ jbooleanArray array = env_->NewBooleanArray(kLength);
+ ASSERT_TRUE(array != nullptr);
+ jboolean elements[kLength];
+ env_->SetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
+ reinterpret_cast<jbyte*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected byte[]"
+ : "attempt to set region of byte primitive array elements with an object of type boolean[]");
+ env_->SetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
+ reinterpret_cast<jshort*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected short[]"
+ : "attempt to set region of short primitive array elements with an object of type boolean[]");
+ env_->SetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
+ reinterpret_cast<jchar*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected char[]"
+ : "attempt to set region of char primitive array elements with an object of type boolean[]");
+ env_->SetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
+ reinterpret_cast<jint*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected int[]"
+ : "attempt to set region of int primitive array elements with an object of type boolean[]");
+ env_->SetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
+ reinterpret_cast<jlong*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected long[]"
+ : "attempt to set region of long primitive array elements with an object of type boolean[]");
+ env_->SetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
+ reinterpret_cast<jfloat*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected float[]"
+ : "attempt to set region of float primitive array elements with an object of type boolean[]");
+ env_->SetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
+ reinterpret_cast<jdouble*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected double[]"
+ : "attempt to set region of double primitive array elements with an object of type boolean[]");
+ jbyteArray array2 = env_->NewByteArray(10);
+ env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
+ reinterpret_cast<jboolean*>(elements));
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type byte[] expected boolean[]"
+ : "attempt to set region of boolean primitive array elements with an object of type byte[]");
+ jobject object = env_->NewStringUTF("Test String");
+ env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
+ reinterpret_cast<jboolean*>(elements));
+ jni_abort_catcher.Check(check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "attempt to set region of boolean primitive array elements with an object of type "
+ "java.lang.String");
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
+ void NewObjectArrayBadArguments(bool check_jni) {
+ bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
+ CheckJniAbortCatcher jni_abort_catcher;
+
+ jclass element_class = env_->FindClass("java/lang/String");
+ ASSERT_NE(element_class, nullptr);
+
+ env_->NewObjectArray(-1, element_class, nullptr);
+ jni_abort_catcher.Check(check_jni ? "negative jsize: -1" : "negative array length: -1");
+
+ env_->NewObjectArray(std::numeric_limits<jint>::min(), element_class, nullptr);
+ jni_abort_catcher.Check(check_jni ? "negative jsize: -2147483648"
+ : "negative array length: -2147483648");
+
+ EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
+ }
+
JavaVMExt* vm_;
JNIEnv* env_;
jclass aioobe_;
@@ -125,48 +621,8 @@ TEST_F(JniInternalTest, GetVersion) {
}
TEST_F(JniInternalTest, FindClass) {
- // Reference types...
- ExpectClassFound("java/lang/String");
- // ...for arrays too, where you must include "L;".
- ExpectClassFound("[Ljava/lang/String;");
- // Primitive arrays are okay too, if the primitive type is valid.
- ExpectClassFound("[C");
-
- {
- CheckJniAbortCatcher check_jni_abort_catcher;
- env_->FindClass(nullptr);
- check_jni_abort_catcher.Check("name == null");
-
- // We support . as well as / for compatibility, if -Xcheck:jni is off.
- ExpectClassFound("java.lang.String");
- check_jni_abort_catcher.Check("illegal class name 'java.lang.String'");
- ExpectClassNotFound("Ljava.lang.String;");
- check_jni_abort_catcher.Check("illegal class name 'Ljava.lang.String;'");
- ExpectClassFound("[Ljava.lang.String;");
- check_jni_abort_catcher.Check("illegal class name '[Ljava.lang.String;'");
- ExpectClassNotFound("[java.lang.String");
- check_jni_abort_catcher.Check("illegal class name '[java.lang.String'");
-
- // You can't include the "L;" in a JNI class descriptor.
- ExpectClassNotFound("Ljava/lang/String;");
- check_jni_abort_catcher.Check("illegal class name 'Ljava/lang/String;'");
-
- // But you must include it for an array of any reference type.
- ExpectClassNotFound("[java/lang/String");
- check_jni_abort_catcher.Check("illegal class name '[java/lang/String'");
-
- ExpectClassNotFound("[K");
- check_jni_abort_catcher.Check("illegal class name '[K'");
-
- // Void arrays aren't allowed.
- ExpectClassNotFound("[V");
- check_jni_abort_catcher.Check("illegal class name '[V'");
- }
-
- // But primitive types aren't allowed...
- ExpectClassNotFound("C");
- ExpectClassNotFound("V");
- ExpectClassNotFound("K");
+ FindClassTest(false);
+ FindClassTest(true);
}
TEST_F(JniInternalTest, GetFieldID) {
@@ -208,16 +664,8 @@ TEST_F(JniInternalTest, GetFieldID) {
ExpectException(jlnsfe);
// Bad arguments.
- CheckJniAbortCatcher check_jni_abort_catcher;
- fid = env_->GetFieldID(nullptr, "count", "I");
- EXPECT_EQ(nullptr, fid);
- check_jni_abort_catcher.Check("java_class == null");
- fid = env_->GetFieldID(c, nullptr, "I");
- EXPECT_EQ(nullptr, fid);
- check_jni_abort_catcher.Check("name == null");
- fid = env_->GetFieldID(c, "count", nullptr);
- EXPECT_EQ(nullptr, fid);
- check_jni_abort_catcher.Check("sig == null");
+ GetFieldIdBadArgumentTest(false);
+ GetFieldIdBadArgumentTest(true);
}
TEST_F(JniInternalTest, GetStaticFieldID) {
@@ -253,16 +701,8 @@ TEST_F(JniInternalTest, GetStaticFieldID) {
ExpectException(jlnsfe);
// Bad arguments.
- CheckJniAbortCatcher check_jni_abort_catcher;
- fid = env_->GetStaticFieldID(nullptr, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
- EXPECT_EQ(nullptr, fid);
- check_jni_abort_catcher.Check("java_class == null");
- fid = env_->GetStaticFieldID(c, nullptr, "Ljava/util/Comparator;");
- EXPECT_EQ(nullptr, fid);
- check_jni_abort_catcher.Check("name == null");
- fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", nullptr);
- EXPECT_EQ(nullptr, fid);
- check_jni_abort_catcher.Check("sig == null");
+ GetStaticFieldIdBadArgumentTest(false);
+ GetStaticFieldIdBadArgumentTest(true);
}
TEST_F(JniInternalTest, GetMethodID) {
@@ -302,16 +742,8 @@ TEST_F(JniInternalTest, GetMethodID) {
EXPECT_FALSE(env_->ExceptionCheck());
// Bad arguments.
- CheckJniAbortCatcher check_jni_abort_catcher;
- method = env_->GetMethodID(nullptr, "<init>", "(Ljava/lang/String;)V");
- EXPECT_EQ(nullptr, method);
- check_jni_abort_catcher.Check("java_class == null");
- method = env_->GetMethodID(jlnsme, nullptr, "(Ljava/lang/String;)V");
- EXPECT_EQ(nullptr, method);
- check_jni_abort_catcher.Check("name == null");
- method = env_->GetMethodID(jlnsme, "<init>", nullptr);
- EXPECT_EQ(nullptr, method);
- check_jni_abort_catcher.Check("sig == null");
+ GetMethodIdBadArgumentTest(false);
+ GetMethodIdBadArgumentTest(true);
}
TEST_F(JniInternalTest, GetStaticMethodID) {
@@ -340,16 +772,8 @@ TEST_F(JniInternalTest, GetStaticMethodID) {
EXPECT_FALSE(env_->ExceptionCheck());
// Bad arguments.
- CheckJniAbortCatcher check_jni_abort_catcher;
- method = env_->GetStaticMethodID(nullptr, "valueOf", "(I)Ljava/lang/String;");
- EXPECT_EQ(nullptr, method);
- check_jni_abort_catcher.Check("java_class == null");
- method = env_->GetStaticMethodID(jlstring, nullptr, "(I)Ljava/lang/String;");
- EXPECT_EQ(nullptr, method);
- check_jni_abort_catcher.Check("name == null");
- method = env_->GetStaticMethodID(jlstring, "valueOf", nullptr);
- EXPECT_EQ(nullptr, method);
- check_jni_abort_catcher.Check("sig == null");
+ GetStaticMethodIdBadArgumentTest(false);
+ GetStaticMethodIdBadArgumentTest(true);
}
TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
@@ -370,13 +794,8 @@ TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
ASSERT_EQ(4, env_->GetIntField(s, fid2));
// Bad arguments.
- CheckJniAbortCatcher check_jni_abort_catcher;
- field = env_->ToReflectedField(c, nullptr, JNI_FALSE);
- EXPECT_EQ(field, nullptr);
- check_jni_abort_catcher.Check("fid == null");
- fid2 = env_->FromReflectedField(nullptr);
- ASSERT_EQ(fid2, nullptr);
- check_jni_abort_catcher.Check("jlr_field == null");
+ GetFromReflectedField_ToReflectedFieldBadArgumentTest(false);
+ GetFromReflectedField_ToReflectedFieldBadArgumentTest(true);
}
TEST_F(JniInternalTest, FromReflectedMethod_ToReflectedMethod) {
@@ -417,13 +836,8 @@ TEST_F(JniInternalTest, FromReflectedMethod_ToReflectedMethod) {
ASSERT_EQ(4, env_->CallIntMethod(s, mid2));
// Bad arguments.
- CheckJniAbortCatcher check_jni_abort_catcher;
- method = env_->ToReflectedMethod(c, nullptr, JNI_FALSE);
- EXPECT_EQ(method, nullptr);
- check_jni_abort_catcher.Check("mid == null");
- mid2 = env_->FromReflectedMethod(method);
- ASSERT_EQ(mid2, nullptr);
- check_jni_abort_catcher.Check("jlr_method == null");
+ GetFromReflectedMethod_ToReflectedMethodBadArgumentTest(false);
+ GetFromReflectedMethod_ToReflectedMethodBadArgumentTest(true);
}
static void BogusMethod() {
@@ -498,23 +912,11 @@ TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
}
EXPECT_FALSE(env_->ExceptionCheck());
- // Passing a class of null is a failure.
- {
- JNINativeMethod methods[] = { };
- EXPECT_EQ(env_->RegisterNatives(nullptr, methods, 0), JNI_ERR);
- check_jni_abort_catcher.Check("java_class == null");
- }
-
- // Passing methods as null is a failure.
- EXPECT_EQ(env_->RegisterNatives(jlobject, nullptr, 1), JNI_ERR);
- check_jni_abort_catcher.Check("methods == null");
-
- // Unregisters null is a failure.
- EXPECT_EQ(env_->UnregisterNatives(nullptr), JNI_ERR);
- check_jni_abort_catcher.Check("java_class == null");
-
// Unregistering a class with no natives is a warning.
EXPECT_EQ(env_->UnregisterNatives(jlnsme), JNI_OK);
+
+ RegisterAndUnregisterNativesBadArguments(false, &check_jni_abort_catcher);
+ RegisterAndUnregisterNativesBadArguments(true, &check_jni_abort_catcher);
}
#define EXPECT_PRIMITIVE_ARRAY(new_fn, \
@@ -528,6 +930,7 @@ TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
\
{ \
CheckJniAbortCatcher jni_abort_catcher; \
+ down_cast<JNIEnvExt*>(env_)->SetCheckJniEnabled(false); \
/* Allocate an negative sized array and check it has the right failure type. */ \
EXPECT_EQ(env_->new_fn(-1), nullptr); \
jni_abort_catcher.Check("negative array length: -1"); \
@@ -550,6 +953,7 @@ TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
jni_abort_catcher.Check("buf == null"); \
env_->set_region_fn(a, 0, size, nullptr); \
jni_abort_catcher.Check("buf == null"); \
+ down_cast<JNIEnvExt*>(env_)->SetCheckJniEnabled(true); \
} \
/* Allocate an array and check it has the right type and length. */ \
scalar_type ## Array a = env_->new_fn(size); \
@@ -654,189 +1058,28 @@ TEST_F(JniInternalTest, ShortArrays) {
}
TEST_F(JniInternalTest, GetPrimitiveArrayElementsOfWrongType) {
- CheckJniAbortCatcher jni_abort_catcher;
- jbooleanArray array = env_->NewBooleanArray(10);
- jboolean is_copy;
- EXPECT_EQ(env_->GetByteArrayElements(reinterpret_cast<jbyteArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get byte primitive array elements with an object of type boolean[]");
- EXPECT_EQ(env_->GetShortArrayElements(reinterpret_cast<jshortArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get short primitive array elements with an object of type boolean[]");
- EXPECT_EQ(env_->GetCharArrayElements(reinterpret_cast<jcharArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get char primitive array elements with an object of type boolean[]");
- EXPECT_EQ(env_->GetIntArrayElements(reinterpret_cast<jintArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get int primitive array elements with an object of type boolean[]");
- EXPECT_EQ(env_->GetLongArrayElements(reinterpret_cast<jlongArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get long primitive array elements with an object of type boolean[]");
- EXPECT_EQ(env_->GetFloatArrayElements(reinterpret_cast<jfloatArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get float primitive array elements with an object of type boolean[]");
- EXPECT_EQ(env_->GetDoubleArrayElements(reinterpret_cast<jdoubleArray>(array), &is_copy), nullptr);
- jni_abort_catcher.Check(
- "attempt to get double primitive array elements with an object of type boolean[]");
- jbyteArray array2 = env_->NewByteArray(10);
- EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), &is_copy),
- nullptr);
- jni_abort_catcher.Check(
- "attempt to get boolean primitive array elements with an object of type byte[]");
- jobject object = env_->NewStringUTF("Test String");
- EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), &is_copy),
- nullptr);
- jni_abort_catcher.Check(
- "attempt to get boolean primitive array elements with an object of type java.lang.String");
+ GetPrimitiveArrayElementsOfWrongType(false);
+ GetPrimitiveArrayElementsOfWrongType(true);
}
TEST_F(JniInternalTest, ReleasePrimitiveArrayElementsOfWrongType) {
- CheckJniAbortCatcher jni_abort_catcher;
- jbooleanArray array = env_->NewBooleanArray(10);
- ASSERT_TRUE(array != nullptr);
- jboolean is_copy;
- jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
- ASSERT_TRUE(elements != nullptr);
- env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
- reinterpret_cast<jbyte*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release byte primitive array elements with an object of type boolean[]");
- env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
- reinterpret_cast<jshort*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release short primitive array elements with an object of type boolean[]");
- env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
- reinterpret_cast<jchar*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release char primitive array elements with an object of type boolean[]");
- env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
- reinterpret_cast<jint*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release int primitive array elements with an object of type boolean[]");
- env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
- reinterpret_cast<jlong*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release long primitive array elements with an object of type boolean[]");
- env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
- reinterpret_cast<jfloat*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release float primitive array elements with an object of type boolean[]");
- env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
- reinterpret_cast<jdouble*>(elements), 0);
- jni_abort_catcher.Check(
- "attempt to release double primitive array elements with an object of type boolean[]");
- jbyteArray array2 = env_->NewByteArray(10);
- env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), elements, 0);
- jni_abort_catcher.Check(
- "attempt to release boolean primitive array elements with an object of type byte[]");
- jobject object = env_->NewStringUTF("Test String");
- env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
- jni_abort_catcher.Check(
- "attempt to release boolean primitive array elements with an object of type "
- "java.lang.String");
+ ReleasePrimitiveArrayElementsOfWrongType(false);
+ ReleasePrimitiveArrayElementsOfWrongType(true);
}
+
TEST_F(JniInternalTest, GetReleasePrimitiveArrayCriticalOfWrongType) {
- CheckJniAbortCatcher jni_abort_catcher;
- jobject object = env_->NewStringUTF("Test String");
- jboolean is_copy;
- void* elements = env_->GetPrimitiveArrayCritical(reinterpret_cast<jarray>(object), &is_copy);
- jni_abort_catcher.Check("expected primitive array, given java.lang.String");
- env_->ReleasePrimitiveArrayCritical(reinterpret_cast<jarray>(object), elements, 0);
- jni_abort_catcher.Check("expected primitive array, given java.lang.String");
+ GetReleasePrimitiveArrayCriticalOfWrongType(false);
+ GetReleasePrimitiveArrayCriticalOfWrongType(true);
}
TEST_F(JniInternalTest, GetPrimitiveArrayRegionElementsOfWrongType) {
- CheckJniAbortCatcher jni_abort_catcher;
- constexpr size_t kLength = 10;
- jbooleanArray array = env_->NewBooleanArray(kLength);
- ASSERT_TRUE(array != nullptr);
- jboolean elements[kLength];
- env_->GetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
- reinterpret_cast<jbyte*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of byte primitive array elements with an object of type boolean[]");
- env_->GetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
- reinterpret_cast<jshort*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of short primitive array elements with an object of type boolean[]");
- env_->GetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
- reinterpret_cast<jchar*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of char primitive array elements with an object of type boolean[]");
- env_->GetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
- reinterpret_cast<jint*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of int primitive array elements with an object of type boolean[]");
- env_->GetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
- reinterpret_cast<jlong*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of long primitive array elements with an object of type boolean[]");
- env_->GetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
- reinterpret_cast<jfloat*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of float primitive array elements with an object of type boolean[]");
- env_->GetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
- reinterpret_cast<jdouble*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of double primitive array elements with an object of type boolean[]");
- jbyteArray array2 = env_->NewByteArray(10);
- env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
- reinterpret_cast<jboolean*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of boolean primitive array elements with an object of type byte[]");
- jobject object = env_->NewStringUTF("Test String");
- env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
- reinterpret_cast<jboolean*>(elements));
- jni_abort_catcher.Check(
- "attempt to get region of boolean primitive array elements with an object of type "
- "java.lang.String");
+ GetPrimitiveArrayRegionElementsOfWrongType(false);
+ GetPrimitiveArrayRegionElementsOfWrongType(true);
}
TEST_F(JniInternalTest, SetPrimitiveArrayRegionElementsOfWrongType) {
- CheckJniAbortCatcher jni_abort_catcher;
- constexpr size_t kLength = 10;
- jbooleanArray array = env_->NewBooleanArray(kLength);
- ASSERT_TRUE(array != nullptr);
- jboolean elements[kLength];
- env_->SetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
- reinterpret_cast<jbyte*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of byte primitive array elements with an object of type boolean[]");
- env_->SetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
- reinterpret_cast<jshort*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of short primitive array elements with an object of type boolean[]");
- env_->SetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
- reinterpret_cast<jchar*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of char primitive array elements with an object of type boolean[]");
- env_->SetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
- reinterpret_cast<jint*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of int primitive array elements with an object of type boolean[]");
- env_->SetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
- reinterpret_cast<jlong*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of long primitive array elements with an object of type boolean[]");
- env_->SetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
- reinterpret_cast<jfloat*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of float primitive array elements with an object of type boolean[]");
- env_->SetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
- reinterpret_cast<jdouble*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of double primitive array elements with an object of type boolean[]");
- jbyteArray array2 = env_->NewByteArray(10);
- env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
- reinterpret_cast<jboolean*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of boolean primitive array elements with an object of type byte[]");
- jobject object = env_->NewStringUTF("Test String");
- env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
- reinterpret_cast<jboolean*>(elements));
- jni_abort_catcher.Check(
- "attempt to set region of boolean primitive array elements with an object of type "
- "java.lang.String");
+ SetPrimitiveArrayRegionElementsOfWrongType(false);
+ SetPrimitiveArrayRegionElementsOfWrongType(true);
}
TEST_F(JniInternalTest, NewObjectArray) {
@@ -857,12 +1100,8 @@ TEST_F(JniInternalTest, NewObjectArray) {
EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(a, 0), nullptr));
// Negative array length checks.
- CheckJniAbortCatcher jni_abort_catcher;
- env_->NewObjectArray(-1, element_class, nullptr);
- jni_abort_catcher.Check("negative array length: -1");
-
- env_->NewObjectArray(std::numeric_limits<jint>::min(), element_class, nullptr);
- jni_abort_catcher.Check("negative array length: -2147483648");
+ NewObjectArrayBadArguments(false);
+ NewObjectArrayBadArguments(true);
}
TEST_F(JniInternalTest, NewObjectArrayWithPrimitiveClasses) {
@@ -872,6 +1111,7 @@ TEST_F(JniInternalTest, NewObjectArrayWithPrimitiveClasses) {
};
ASSERT_EQ(strlen(primitive_descriptors), arraysize(primitive_names));
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
CheckJniAbortCatcher jni_abort_catcher;
for (size_t i = 0; i < strlen(primitive_descriptors); ++i) {
env_->NewObjectArray(0, nullptr, nullptr);
@@ -881,6 +1121,16 @@ TEST_F(JniInternalTest, NewObjectArrayWithPrimitiveClasses) {
std::string error_msg(StringPrintf("not an object type: %s", primitive_names[i]));
jni_abort_catcher.Check(error_msg.c_str());
}
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ for (size_t i = 0; i < strlen(primitive_descriptors); ++i) {
+ env_->NewObjectArray(0, nullptr, nullptr);
+ jni_abort_catcher.Check("NewObjectArray received NULL jclass");
+ jclass primitive_class = GetPrimitiveClass(primitive_descriptors[i]);
+ env_->NewObjectArray(1, primitive_class, nullptr);
+ std::string error_msg(StringPrintf("not an object type: %s", primitive_names[i]));
+ jni_abort_catcher.Check(error_msg.c_str());
+ }
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
TEST_F(JniInternalTest, NewObjectArrayWithInitialValue) {
@@ -940,8 +1190,13 @@ TEST_F(JniInternalTest, GetSuperclass) {
// Null as class should fail.
CheckJniAbortCatcher jni_abort_catcher;
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
EXPECT_EQ(env_->GetSuperclass(nullptr), nullptr);
jni_abort_catcher.Check("java_class == null");
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ EXPECT_EQ(env_->GetSuperclass(nullptr), nullptr);
+ jni_abort_catcher.Check("GetSuperclass received NULL jclass");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
TEST_F(JniInternalTest, IsAssignableFrom) {
@@ -975,10 +1230,17 @@ TEST_F(JniInternalTest, IsAssignableFrom) {
// Null as either class should fail.
CheckJniAbortCatcher jni_abort_catcher;
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
EXPECT_EQ(env_->IsAssignableFrom(nullptr, string_class), JNI_FALSE);
jni_abort_catcher.Check("java_class1 == null");
EXPECT_EQ(env_->IsAssignableFrom(object_class, nullptr), JNI_FALSE);
jni_abort_catcher.Check("java_class2 == null");
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ EXPECT_EQ(env_->IsAssignableFrom(nullptr, string_class), JNI_FALSE);
+ jni_abort_catcher.Check("IsAssignableFrom received NULL jclass");
+ EXPECT_EQ(env_->IsAssignableFrom(object_class, nullptr), JNI_FALSE);
+ jni_abort_catcher.Check("IsAssignableFrom received NULL jclass");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
TEST_F(JniInternalTest, GetObjectRefType) {
@@ -1063,10 +1325,17 @@ TEST_F(JniInternalTest, NewStringNullCharsNonzeroLength) {
TEST_F(JniInternalTest, NewStringNegativeLength) {
CheckJniAbortCatcher jni_abort_catcher;
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
env_->NewString(nullptr, -1);
jni_abort_catcher.Check("char_count < 0: -1");
env_->NewString(nullptr, std::numeric_limits<jint>::min());
jni_abort_catcher.Check("char_count < 0: -2147483648");
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ env_->NewString(nullptr, -1);
+ jni_abort_catcher.Check("negative jsize: -1");
+ env_->NewString(nullptr, std::numeric_limits<jint>::min());
+ jni_abort_catcher.Check("negative jsize: -2147483648");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
TEST_F(JniInternalTest, GetStringLength_GetStringUTFLength) {
@@ -1124,10 +1393,17 @@ TEST_F(JniInternalTest, GetStringRegion_GetStringUTFRegion) {
TEST_F(JniInternalTest, GetStringUTFChars_ReleaseStringUTFChars) {
// Passing in a nullptr jstring is ignored normally, but caught by -Xcheck:jni.
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
{
CheckJniAbortCatcher check_jni_abort_catcher;
EXPECT_EQ(env_->GetStringUTFChars(nullptr, nullptr), nullptr);
- check_jni_abort_catcher.Check("GetStringUTFChars received null jstring");
+ }
+ {
+ CheckJniAbortCatcher check_jni_abort_catcher;
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ EXPECT_EQ(env_->GetStringUTFChars(nullptr, nullptr), nullptr);
+ check_jni_abort_catcher.Check("GetStringUTFChars received NULL jstring");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
jstring s = env_->NewStringUTF("hello");
@@ -1222,10 +1498,17 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
// Null as array should fail.
CheckJniAbortCatcher jni_abort_catcher;
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
EXPECT_EQ(nullptr, env_->GetObjectArrayElement(nullptr, 0));
jni_abort_catcher.Check("java_array == null");
env_->SetObjectArrayElement(nullptr, 0, nullptr);
jni_abort_catcher.Check("java_array == null");
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ EXPECT_EQ(nullptr, env_->GetObjectArrayElement(nullptr, 0));
+ jni_abort_catcher.Check("jarray was NULL");
+ env_->SetObjectArrayElement(nullptr, 0, nullptr);
+ jni_abort_catcher.Check("jarray was NULL");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
#define EXPECT_STATIC_PRIMITIVE_FIELD(type, field_name, sig, value1, value2) \
@@ -1237,15 +1520,28 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
env_->SetStatic ## type ## Field(c, fid, value2); \
EXPECT_EQ(value2, env_->GetStatic ## type ## Field(c, fid)); \
\
+ bool old_check_jni = vm_->SetCheckJniEnabled(false); \
+ { \
+ CheckJniAbortCatcher jni_abort_catcher; \
+ env_->GetStatic ## type ## Field(nullptr, fid); \
+ env_->SetStatic ## type ## Field(nullptr, fid, value1); \
+ } \
CheckJniAbortCatcher jni_abort_catcher; \
- env_->GetStatic ## type ## Field(nullptr, fid); \
- jni_abort_catcher.Check("received null jclass"); \
- env_->SetStatic ## type ## Field(nullptr, fid, value1); \
- jni_abort_catcher.Check("received null jclass"); \
env_->GetStatic ## type ## Field(c, nullptr); \
jni_abort_catcher.Check("fid == null"); \
env_->SetStatic ## type ## Field(c, nullptr, value1); \
jni_abort_catcher.Check("fid == null"); \
+ \
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true)); \
+ env_->GetStatic ## type ## Field(nullptr, fid); \
+ jni_abort_catcher.Check("received NULL jclass"); \
+ env_->SetStatic ## type ## Field(nullptr, fid, value1); \
+ jni_abort_catcher.Check("received NULL jclass"); \
+ env_->GetStatic ## type ## Field(c, nullptr); \
+ jni_abort_catcher.Check("jfieldID was NULL"); \
+ env_->SetStatic ## type ## Field(c, nullptr, value1); \
+ jni_abort_catcher.Check("jfieldID was NULL"); \
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni)); \
} while (false)
#define EXPECT_PRIMITIVE_FIELD(instance, type, field_name, sig, value1, value2) \
@@ -1257,6 +1553,7 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
env_->Set ## type ## Field(instance, fid, value2); \
EXPECT_EQ(value2, env_->Get ## type ## Field(instance, fid)); \
\
+ bool old_check_jni = vm_->SetCheckJniEnabled(false); \
CheckJniAbortCatcher jni_abort_catcher; \
env_->Get ## type ## Field(nullptr, fid); \
jni_abort_catcher.Check("obj == null"); \
@@ -1266,6 +1563,16 @@ TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
jni_abort_catcher.Check("fid == null"); \
env_->Set ## type ## Field(instance, nullptr, value1); \
jni_abort_catcher.Check("fid == null"); \
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true)); \
+ env_->Get ## type ## Field(nullptr, fid); \
+ jni_abort_catcher.Check("field operation on NULL object:"); \
+ env_->Set ## type ## Field(nullptr, fid, value1); \
+ jni_abort_catcher.Check("field operation on NULL object:"); \
+ env_->Get ## type ## Field(instance, nullptr); \
+ jni_abort_catcher.Check("jfieldID was NULL"); \
+ env_->Set ## type ## Field(instance, nullptr, value1); \
+ jni_abort_catcher.Check("jfieldID was NULL"); \
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni)); \
} while (false)
@@ -1357,12 +1664,17 @@ TEST_F(JniInternalTest, DeleteLocalRef) {
// Currently, deleting an already-deleted reference is just a CheckJNI warning.
{
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
+ {
+ CheckJniAbortCatcher check_jni_abort_catcher;
+ env_->DeleteLocalRef(s);
+ }
CheckJniAbortCatcher check_jni_abort_catcher;
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
env_->DeleteLocalRef(s);
-
- std::string expected(StringPrintf("native code passing in reference to "
- "invalid local reference: %p", s));
+ std::string expected(StringPrintf("jobject is an invalid local reference: %p", s));
check_jni_abort_catcher.Check(expected.c_str());
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
s = env_->NewStringUTF("");
@@ -1453,12 +1765,17 @@ TEST_F(JniInternalTest, DeleteGlobalRef) {
// Currently, deleting an already-deleted reference is just a CheckJNI warning.
{
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
+ {
+ CheckJniAbortCatcher check_jni_abort_catcher;
+ env_->DeleteGlobalRef(o);
+ }
CheckJniAbortCatcher check_jni_abort_catcher;
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
env_->DeleteGlobalRef(o);
-
- std::string expected(StringPrintf("native code passing in reference to "
- "invalid global reference: %p", o));
+ std::string expected(StringPrintf("jobject is an invalid global reference: %p", o));
check_jni_abort_catcher.Check(expected.c_str());
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
jobject o1 = env_->NewGlobalRef(s);
@@ -1498,12 +1815,17 @@ TEST_F(JniInternalTest, DeleteWeakGlobalRef) {
// Currently, deleting an already-deleted reference is just a CheckJNI warning.
{
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
+ {
+ CheckJniAbortCatcher check_jni_abort_catcher;
+ env_->DeleteWeakGlobalRef(o);
+ }
CheckJniAbortCatcher check_jni_abort_catcher;
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
env_->DeleteWeakGlobalRef(o);
-
- std::string expected(StringPrintf("native code passing in reference to "
- "invalid weak global reference: %p", o));
+ std::string expected(StringPrintf("jobject is an invalid weak global reference: %p", o));
check_jni_abort_catcher.Check(expected.c_str());
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
jobject o1 = env_->NewWeakGlobalRef(s);
@@ -1522,8 +1844,6 @@ TEST_F(JniInternalTest, ExceptionDescribe) {
}
TEST_F(JniInternalTest, Throw) {
- EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
-
jclass exception_class = env_->FindClass("java/lang/RuntimeException");
ASSERT_TRUE(exception_class != nullptr);
jthrowable exception = reinterpret_cast<jthrowable>(env_->AllocObject(exception_class));
@@ -1534,11 +1854,18 @@ TEST_F(JniInternalTest, Throw) {
jthrowable thrown_exception = env_->ExceptionOccurred();
env_->ExceptionClear();
EXPECT_TRUE(env_->IsSameObject(exception, thrown_exception));
-}
-TEST_F(JniInternalTest, ThrowNew) {
+ // Bad argument.
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ CheckJniAbortCatcher check_jni_abort_catcher;
+ EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
+ check_jni_abort_catcher.Check("Throw received NULL jthrowable");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
+}
+TEST_F(JniInternalTest, ThrowNew) {
jclass exception_class = env_->FindClass("java/lang/RuntimeException");
ASSERT_TRUE(exception_class != nullptr);
@@ -1555,6 +1882,16 @@ TEST_F(JniInternalTest, ThrowNew) {
thrown_exception = env_->ExceptionOccurred();
env_->ExceptionClear();
EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, exception_class));
+
+ // Bad argument.
+ bool old_check_jni = vm_->SetCheckJniEnabled(false);
+ CheckJniAbortCatcher check_jni_abort_catcher;
+ EXPECT_EQ(JNI_ERR, env_->ThrowNew(nullptr, nullptr));
+ check_jni_abort_catcher.Check("c == null");
+ EXPECT_FALSE(vm_->SetCheckJniEnabled(true));
+ EXPECT_EQ(JNI_ERR, env_->ThrowNew(nullptr, nullptr));
+ check_jni_abort_catcher.Check("ThrowNew received NULL jclass");
+ EXPECT_TRUE(vm_->SetCheckJniEnabled(old_check_jni));
}
TEST_F(JniInternalTest, NewDirectBuffer_GetDirectBufferAddress_GetDirectBufferCapacity) {