diff options
author | Andreas Gampe <agampe@google.com> | 2014-08-11 18:51:53 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-08-13 22:19:48 -0700 |
commit | 718ac65aa78403124c2269f0dcadd341a18b8efe (patch) | |
tree | 64bc497fb0366c7df8464c972601132e84579954 /test/004-JniTest | |
parent | e8bf3df2bcc61c12a7e66b4995a083f9ed3939e0 (diff) | |
download | art-718ac65aa78403124c2269f0dcadd341a18b8efe.zip art-718ac65aa78403124c2269f0dcadd341a18b8efe.tar.gz art-718ac65aa78403124c2269f0dcadd341a18b8efe.tar.bz2 |
ART: Tolerate shallow call stack in VMStack_getCallingClassLoader
When the call stack does not have the three methods we expect,
the visitor will return a nullptr value.
Add a test to JniTest (and refactor the test a little for code reuse).
Bug: 16867274
(cherry picked from commit 61bf6a1c80bf797af5d7911ff71fc367fdb36742)
Change-Id: I5fb8f91f372a41e0bc11ef9f70640834591afa53
Diffstat (limited to 'test/004-JniTest')
-rw-r--r-- | test/004-JniTest/jni_test.cc | 195 | ||||
-rw-r--r-- | test/004-JniTest/src/Main.java | 7 |
2 files changed, 117 insertions, 85 deletions
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc index 554712a..9a2fbdf 100644 --- a/test/004-JniTest/jni_test.cc +++ b/test/004-JniTest/jni_test.cc @@ -28,162 +28,133 @@ static JavaVM* jvm = NULL; extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { - assert(vm != NULL); - assert(jvm == NULL); + assert(vm != nullptr); + assert(jvm == nullptr); jvm = vm; return JNI_VERSION_1_6; } -static void* testFindClassOnAttachedNativeThread(void*) { - assert(jvm != NULL); +static void* AttachHelper(void* arg) { + assert(jvm != nullptr); - JNIEnv* env = NULL; + JNIEnv* env = nullptr; JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL }; int attach_result = jvm->AttachCurrentThread(&env, &args); assert(attach_result == 0); - jclass clazz = env->FindClass("Main"); - assert(clazz != NULL); - assert(!env->ExceptionCheck()); - - jobjectArray array = env->NewObjectArray(0, clazz, NULL); - assert(array != NULL); - assert(!env->ExceptionCheck()); + typedef void (*Fn)(JNIEnv*); + Fn fn = reinterpret_cast<Fn>(arg); + fn(env); int detach_result = jvm->DetachCurrentThread(); assert(detach_result == 0); - return NULL; + return nullptr; } -// http://b/10994325 -extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*, - jclass) { +static void PthreadHelper(void (*fn)(JNIEnv*)) { pthread_t pthread; - int pthread_create_result = pthread_create(&pthread, - NULL, - testFindClassOnAttachedNativeThread, - NULL); + int pthread_create_result = pthread_create(&pthread, nullptr, AttachHelper, + reinterpret_cast<void*>(fn)); assert(pthread_create_result == 0); - int pthread_join_result = pthread_join(pthread, NULL); + int pthread_join_result = pthread_join(pthread, nullptr); assert(pthread_join_result == 0); } -static void* testFindFieldOnAttachedNativeThread(void*) { - assert(jvm != NULL); +static void testFindClassOnAttachedNativeThread(JNIEnv* env) { + jclass clazz = env->FindClass("Main"); + assert(clazz != nullptr); + assert(!env->ExceptionCheck()); - JNIEnv* env = NULL; - JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL }; - int attach_result = jvm->AttachCurrentThread(&env, &args); - assert(attach_result == 0); + jobjectArray array = env->NewObjectArray(0, clazz, nullptr); + assert(array != nullptr); + assert(!env->ExceptionCheck()); +} +// http://b/10994325 +extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*, jclass) { + PthreadHelper(&testFindClassOnAttachedNativeThread); +} + +static void testFindFieldOnAttachedNativeThread(JNIEnv* env) { jclass clazz = env->FindClass("Main"); - assert(clazz != NULL); + assert(clazz != nullptr); assert(!env->ExceptionCheck()); jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z"); - assert(field != NULL); + assert(field != nullptr); assert(!env->ExceptionCheck()); env->SetStaticBooleanField(clazz, field, JNI_TRUE); - - int detach_result = jvm->DetachCurrentThread(); - assert(detach_result == 0); - return NULL; } extern "C" JNIEXPORT void JNICALL Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv*, - jclass) { - pthread_t pthread; - int pthread_create_result = pthread_create(&pthread, - NULL, - testFindFieldOnAttachedNativeThread, - NULL); - assert(pthread_create_result == 0); - int pthread_join_result = pthread_join(pthread, NULL); - assert(pthread_join_result == 0); + jclass) { + PthreadHelper(&testFindFieldOnAttachedNativeThread); } -static void* testReflectFieldGetFromAttachedNativeThread(void*) { - assert(jvm != NULL); - - JNIEnv* env = NULL; - JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL }; - int attach_result = jvm->AttachCurrentThread(&env, &args); - assert(attach_result == 0); - +static void testReflectFieldGetFromAttachedNativeThread(JNIEnv* env) { jclass clazz = env->FindClass("Main"); - assert(clazz != NULL); + assert(clazz != nullptr); assert(!env->ExceptionCheck()); jclass class_clazz = env->FindClass("java/lang/Class"); - assert(class_clazz != NULL); + assert(class_clazz != nullptr); assert(!env->ExceptionCheck()); jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); - assert(getFieldMetodId != NULL); + assert(getFieldMetodId != nullptr); assert(!env->ExceptionCheck()); jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField"); - assert(field_name != NULL); + assert(field_name != nullptr); assert(!env->ExceptionCheck()); jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name); - assert(field != NULL); + assert(field != nullptr); assert(!env->ExceptionCheck()); jclass field_clazz = env->FindClass("java/lang/reflect/Field"); - assert(field_clazz != NULL); + assert(field_clazz != nullptr); assert(!env->ExceptionCheck()); jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean", "(Ljava/lang/Object;)Z"); - assert(getBooleanMetodId != NULL); + assert(getBooleanMetodId != nullptr); assert(!env->ExceptionCheck()); jboolean value = env->CallBooleanMethod(field, getBooleanMetodId, /* ignored */ clazz); assert(value == false); assert(!env->ExceptionCheck()); - - int detach_result = jvm->DetachCurrentThread(); - assert(detach_result == 0); - return NULL; } // http://b/15539150 extern "C" JNIEXPORT void JNICALL Java_Main_testReflectFieldGetFromAttachedNativeThreadNative( JNIEnv*, jclass) { - pthread_t pthread; - int pthread_create_result = pthread_create(&pthread, - NULL, - testReflectFieldGetFromAttachedNativeThread, - NULL); - assert(pthread_create_result == 0); - int pthread_join_result = pthread_join(pthread, NULL); - assert(pthread_join_result == 0); + PthreadHelper(&testReflectFieldGetFromAttachedNativeThread); } // http://b/11243757 extern "C" JNIEXPORT void JNICALL Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, - jclass) { + jclass) { jclass super_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SuperClass"); - assert(super_class != NULL); + assert(super_class != nullptr); jmethodID execute = env->GetStaticMethodID(super_class, "execute", "()V"); - assert(execute != NULL); + assert(execute != nullptr); jclass sub_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SubClass"); - assert(sub_class != NULL); + assert(sub_class != nullptr); env->CallStaticVoidMethod(sub_class, execute); } extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass) { jclass abstract_class = env->FindClass("Main$testGetMirandaMethod_MirandaAbstract"); - assert(abstract_class != NULL); + assert(abstract_class != nullptr); jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z"); - assert(miranda_method != NULL); + assert(miranda_method != nullptr); return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE); } @@ -191,7 +162,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv extern "C" void JNICALL Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass) { std::vector<uint8_t> buffer(1); jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0); - assert(byte_buffer != NULL); + assert(byte_buffer != nullptr); assert(!env->ExceptionCheck()); assert(env->GetDirectBufferAddress(byte_buffer) == &buffer[0]); @@ -202,8 +173,8 @@ constexpr size_t kByteReturnSize = 7; jbyte byte_returns[kByteReturnSize] = { 0, 1, 2, 127, -1, -2, -128 }; extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2, - jbyte b3, jbyte b4, jbyte b5, jbyte b6, - jbyte b7, jbyte b8, jbyte b9, jbyte b10) { + jbyte b3, jbyte b4, jbyte b5, jbyte b6, + jbyte b7, jbyte b8, jbyte b9, jbyte b10) { // We use b1 to drive the output. assert(b2 == 2); assert(b3 == -3); @@ -227,8 +198,8 @@ jshort short_returns[kShortReturnSize] = { 0, 1, 2, 127, 32767, -1, -2, -128, // The weird static_cast is because short int is only guaranteed down to -32767, not Java's -32768. extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2, - jshort s3, jshort s4, jshort s5, jshort s6, - jshort s7, jshort s8, jshort s9, jshort s10) { + jshort s3, jshort s4, jshort s5, jshort s6, + jshort s7, jshort s8, jshort s9, jshort s10) { // We use s1 to drive the output. assert(s2 == 2); assert(s3 == -3); @@ -247,9 +218,9 @@ extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv* env, jclass klass, jshor } extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1, - jboolean b2, jboolean b3, jboolean b4, - jboolean b5, jboolean b6, jboolean b7, - jboolean b8, jboolean b9, jboolean b10) { + jboolean b2, jboolean b3, jboolean b4, + jboolean b5, jboolean b6, jboolean b7, + jboolean b8, jboolean b9, jboolean b10) { // We use b1 to drive the output. assert(b2 == JNI_TRUE); assert(b3 == JNI_FALSE); @@ -269,8 +240,8 @@ constexpr size_t kCharReturnSize = 8; jchar char_returns[kCharReturnSize] = { 0, 1, 2, 127, 255, 256, 15000, 34000 }; extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv* env, jclass klacc, jchar c1, jchar c2, - jchar c3, jchar c4, jchar c5, jchar c6, - jchar c7, jchar c8, jchar c9, jchar c10) { + jchar c3, jchar c4, jchar c5, jchar c6, jchar c7, + jchar c8, jchar c9, jchar c10) { // We use c1 to drive the output. assert(c2 == 'a'); assert(c3 == 'b'); @@ -291,3 +262,57 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_nativeIsAssignableFrom(JNIEnv* e jclass from, jclass to) { return env->IsAssignableFrom(from, to); } + +static void testShallowGetCallingClassLoader(JNIEnv* env) { + // Test direct call. + { + jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); + assert(vmstack_clazz != nullptr); + assert(!env->ExceptionCheck()); + + jmethodID getCallingClassLoaderMethodId = env->GetStaticMethodID(vmstack_clazz, + "getCallingClassLoader", + "()Ljava/lang/ClassLoader;"); + assert(getCallingClassLoaderMethodId != nullptr); + assert(!env->ExceptionCheck()); + + jobject class_loader = env->CallStaticObjectMethod(vmstack_clazz, + getCallingClassLoaderMethodId); + assert(class_loader == nullptr); + assert(!env->ExceptionCheck()); + } + + // Test one-level call. Use System.loadLibrary(). + { + jclass system_clazz = env->FindClass("java/lang/System"); + assert(system_clazz != nullptr); + assert(!env->ExceptionCheck()); + + jmethodID loadLibraryMethodId = env->GetStaticMethodID(system_clazz, "loadLibrary", + "(Ljava/lang/String;)V"); + assert(loadLibraryMethodId != nullptr); + assert(!env->ExceptionCheck()); + + // Create a string object. + jobject library_string = env->NewStringUTF("arttest"); + assert(library_string != nullptr); + assert(!env->ExceptionCheck()); + + env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string); + if (env->ExceptionCheck()) { + // At most we expect UnsatisfiedLinkError. + jthrowable thrown = env->ExceptionOccurred(); + env->ExceptionClear(); + + jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError"); + jclass thrown_class = env->GetObjectClass(thrown); + assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class)); + } + } +} + +// http://b/16867274 +extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetCallingClassLoader(JNIEnv* env, + jclass) { + PthreadHelper(&testShallowGetCallingClassLoader); +} diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java index ae133be..6d7d647 100644 --- a/test/004-JniTest/src/Main.java +++ b/test/004-JniTest/src/Main.java @@ -30,6 +30,7 @@ public class Main { testBooleanMethod(); testCharMethod(); testIsAssignableFromOnPrimitiveTypes(); + testShallowGetCallingClassLoader(); } private static native void testFindClassOnAttachedNativeThread(); @@ -167,4 +168,10 @@ public class Main { } native static boolean nativeIsAssignableFrom(Class<?> from, Class<?> to); + + static void testShallowGetCallingClassLoader() { + nativeTestShallowGetCallingClassLoader(); + } + + native static void nativeTestShallowGetCallingClassLoader(); } |