Fix reflection access check for attached native threads.
Bug: 15539150
(cherry picked from commit 3bd7a6c1716935e758f230e2f199128cb3c28b42)
Change-Id: If7f6e023ef5a38220329cf5644e3a2af12cc1495
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index c08cc30..a1d7f76 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -801,6 +801,10 @@
bool VerifyAccess(mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags) {
NthCallerVisitor visitor(Thread::Current(), 2);
visitor.WalkStack();
+ if (UNLIKELY(visitor.caller == nullptr)) {
+ // The caller is an attached native thread.
+ return (access_flags & kAccPublic) != 0;
+ }
mirror::Class* caller_class = visitor.caller->GetDeclaringClass();
if (((access_flags & kAccPublic) != 0) || (caller_class == declaring_class)) {
diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java
index 3c4ed35..33418a9 100644
--- a/test/JniTest/JniTest.java
+++ b/test/JniTest/JniTest.java
@@ -21,6 +21,7 @@
System.loadLibrary("arttest");
testFindClassOnAttachedNativeThread();
testFindFieldOnAttachedNativeThread();
+ testReflectFieldGetFromAttachedNativeThreadNative();
testCallStaticVoidMethodOnSubClass();
testGetMirandaMethod();
testZeroLengthByteBuffers();
@@ -34,6 +35,10 @@
private static boolean testFindFieldOnAttachedNativeThreadField;
+ private static native void testReflectFieldGetFromAttachedNativeThreadNative();
+
+ public static boolean testReflectFieldGetFromAttachedNativeThreadField;
+
private static void testFindFieldOnAttachedNativeThread() {
testFindFieldOnAttachedNativeThreadNative();
if (!testFindFieldOnAttachedNativeThreadField) {
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
index 024ba53..36cad72 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/JniTest/jni_test.cc
@@ -103,6 +103,66 @@
assert(pthread_join_result == 0);
}
+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);
+
+ jclass clazz = env->FindClass("JniTest");
+ assert(clazz != NULL);
+ assert(!env->ExceptionCheck());
+
+ jclass class_clazz = env->FindClass("java/lang/Class");
+ assert(class_clazz != NULL);
+ assert(!env->ExceptionCheck());
+
+ jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField",
+ "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
+ assert(getFieldMetodId != NULL);
+ assert(!env->ExceptionCheck());
+
+ jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField");
+ assert(field_name != NULL);
+ assert(!env->ExceptionCheck());
+
+ jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name);
+ assert(field != NULL);
+ assert(!env->ExceptionCheck());
+
+ jclass field_clazz = env->FindClass("java/lang/reflect/Field");
+ assert(field_clazz != NULL);
+ assert(!env->ExceptionCheck());
+
+ jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean",
+ "(Ljava/lang/Object;)Z");
+ assert(getBooleanMetodId != NULL);
+ 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_JniTest_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);
+}
+
// http://b/11243757
extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,