diff options
author | Jeff Hao <jeffhao@google.com> | 2014-03-26 15:08:20 -0700 |
---|---|---|
committer | Jeff Hao <jeffhao@google.com> | 2014-03-28 14:27:55 -0700 |
commit | 11d5d8fffe41cc7daadbfa2ca98ecb978f3029af (patch) | |
tree | fae2cf974b502420a942043d135d301aa75967e7 | |
parent | a708e32a9f764a48175e705ec4bcd2201c84f492 (diff) | |
download | art-11d5d8fffe41cc7daadbfa2ca98ecb978f3029af.zip art-11d5d8fffe41cc7daadbfa2ca98ecb978f3029af.tar.gz art-11d5d8fffe41cc7daadbfa2ca98ecb978f3029af.tar.bz2 |
Add access checks to Method and Field reflection.
Art side of this change. Has a corresponding libcore change.
Bug: 13620925
Change-Id: Ie67f802a2a400e8212b489b9a261b7028422d8ba
-rw-r--r-- | runtime/common_throws.cc | 6 | ||||
-rw-r--r-- | runtime/common_throws.h | 5 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Constructor.cc | 7 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Field.cc | 158 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Method.cc | 8 | ||||
-rw-r--r-- | runtime/reflection.cc | 36 | ||||
-rw-r--r-- | runtime/reflection.h | 5 | ||||
-rw-r--r-- | test/046-reflect/expected.txt | 3 | ||||
-rw-r--r-- | test/046-reflect/src/Main.java | 5 | ||||
-rw-r--r-- | test/064-field-access/src/Main.java | 60 | ||||
-rw-r--r-- | test/064-field-access/src/other/ProtectedClass.java | 6 | ||||
-rw-r--r-- | test/064-field-access/src/other/PublicClass.java | 5 | ||||
-rw-r--r-- | test/100-reflect2/expected.txt | 13 | ||||
-rw-r--r-- | test/100-reflect2/src/Main.java | 7 |
14 files changed, 238 insertions, 86 deletions
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 24d16c4..4b6d82b 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -175,6 +175,12 @@ void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...) { va_end(args); } +// IllegalAccessException + +void ThrowIllegalAccessException(const ThrowLocation* throw_location, const char* msg) { + ThrowException(throw_location, "Ljava/lang/IllegalAccessException;", NULL, msg); +} + // IllegalArgumentException void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const char* msg) { diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 792cdef..c06763e 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -92,6 +92,11 @@ void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; +// IllegalAccessException + +void ThrowIllegalAccessException(const ThrowLocation* throw_location, const char* msg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; + // IllegalArgumentException void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const char* msg) diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index b7e8ac2..d28ebd0 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -34,7 +34,8 @@ namespace art { * check. We can also safely assume the constructor isn't associated * with an interface, array, or primitive class. */ -static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) { +static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, + jboolean accessible) { ScopedFastNativeObjectAccess soa(env); mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod); SirtRef<mirror::Class> c(soa.Self(), m->GetDeclaringClass()); @@ -67,14 +68,14 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA } jobject javaReceiver = soa.AddLocalReference<jobject>(receiver); - InvokeMethod(soa, javaMethod, javaReceiver, javaArgs); + InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, accessible); // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod. return javaReceiver; } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;)Ljava/lang/Object;"), + NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;Z)Ljava/lang/Object;"), }; void register_java_lang_reflect_Constructor(JNIEnv* env) { diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 48b58bf..755708e 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -20,6 +20,7 @@ #include "dex_file-inl.h" #include "jni_internal.h" #include "mirror/art_field-inl.h" +#include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "object_utils.h" #include "reflection.h" @@ -27,6 +28,21 @@ namespace art { +static bool ValidateFieldAccess(mirror::ArtField* field, mirror::Object* obj, bool is_set) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (field->IsFinal() && is_set) { + ThrowIllegalAccessException(nullptr, StringPrintf("Cannot set final field: %s", + PrettyField(field).c_str()).c_str()); + return false; + } + if (!ValidateAccess(obj, field->GetDeclaringClass(), field->GetAccessFlags())) { + ThrowIllegalAccessException(nullptr, StringPrintf("Cannot access field: %s", + PrettyField(field).c_str()).c_str()); + return false; + } + return true; +} + static bool GetFieldValue(const ScopedFastNativeObjectAccess& soa, mirror::Object* o, mirror::ArtField* f, Primitive::Type field_type, bool allow_references, JValue* value) @@ -98,7 +114,7 @@ static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa, jobject j_rcv return true; } -static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) { +static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { ScopedFastNativeObjectAccess soa(env); CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization"; mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); @@ -107,6 +123,11 @@ static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) { DCHECK(soa.Self()->IsExceptionPending()); return nullptr; } + // Validate access. + if (!accessible && !ValidateFieldAccess(f, o, false)) { + DCHECK(soa.Self()->IsExceptionPending()); + return nullptr; + } // We now don't expect suspension unless an exception is thrown. // Get the field's value, boxing if necessary. Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType(); @@ -119,7 +140,7 @@ static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) { } static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, - char dst_descriptor) { + char dst_descriptor, jboolean accessible) { ScopedFastNativeObjectAccess soa(env); CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization"; mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); @@ -128,6 +149,13 @@ static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, DCHECK(soa.Self()->IsExceptionPending()); return JValue(); } + + // Validate access. + if (!accessible && !ValidateFieldAccess(f, o, false)) { + DCHECK(soa.Self()->IsExceptionPending()); + return JValue(); + } + // We now don't expect suspension unless an exception is thrown. // Read the value. Primitive::Type field_type = FieldHelper(f).GetTypeAsPrimitiveType(); @@ -147,36 +175,38 @@ static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, return wide_value; } -static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'Z').GetZ(); +static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj, + jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'Z', accessible).GetZ(); } -static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'B').GetB(); +static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'B', accessible).GetB(); } -static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'C').GetC(); +static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'C', accessible).GetC(); } -static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'D').GetD(); +static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj, + jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'D', accessible).GetD(); } -static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'F').GetF(); +static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'F', accessible).GetF(); } -static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'I').GetI(); +static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'I', accessible).GetI(); } -static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'J').GetJ(); +static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'J', accessible).GetJ(); } -static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) { - return GetPrimitiveField(env, javaField, javaObj, 'S').GetS(); +static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { + return GetPrimitiveField(env, javaField, javaObj, 'S', accessible).GetS(); } static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o, @@ -223,7 +253,8 @@ static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o, } } -static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) { +static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue, + jboolean accessible) { ScopedFastNativeObjectAccess soa(env); CHECK(!kMovingFields) << "CheckReceiver may trigger thread suspension for initialization"; mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); @@ -260,11 +291,16 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j DCHECK(soa.Self()->IsExceptionPending()); return; } + // Validate access. + if (!accessible && !ValidateFieldAccess(f, o, true)) { + DCHECK(soa.Self()->IsExceptionPending()); + return; + } SetFieldValue(soa, o, f, field_prim_type, true, unboxed_value); } static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor, - const JValue& new_value) { + const JValue& new_value, jboolean accessible) { ScopedFastNativeObjectAccess soa(env); mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); mirror::Object* o = nullptr; @@ -286,77 +322,91 @@ static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, c return; } + // Validate access. + if (!accessible && !ValidateFieldAccess(f, o, true)) { + DCHECK(soa.Self()->IsExceptionPending()); + return; + } + // Write the value. SetFieldValue(soa, o, f, field_type, false, wide_value); } -static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) { +static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z, + jboolean accessible) { JValue value; value.SetZ(z); - SetPrimitiveField(env, javaField, javaObj, 'Z', value); + SetPrimitiveField(env, javaField, javaObj, 'Z', value, accessible); } -static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b) { +static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b, + jboolean accessible) { JValue value; value.SetB(b); - SetPrimitiveField(env, javaField, javaObj, 'B', value); + SetPrimitiveField(env, javaField, javaObj, 'B', value, accessible); } -static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c) { +static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c, + jboolean accessible) { JValue value; value.SetC(c); - SetPrimitiveField(env, javaField, javaObj, 'C', value); + SetPrimitiveField(env, javaField, javaObj, 'C', value, accessible); } -static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d) { +static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d, + jboolean accessible) { JValue value; value.SetD(d); - SetPrimitiveField(env, javaField, javaObj, 'D', value); + SetPrimitiveField(env, javaField, javaObj, 'D', value, accessible); } -static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f) { +static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f, + jboolean accessible) { JValue value; value.SetF(f); - SetPrimitiveField(env, javaField, javaObj, 'F', value); + SetPrimitiveField(env, javaField, javaObj, 'F', value, accessible); } -static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i) { +static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i, + jboolean accessible) { JValue value; value.SetI(i); - SetPrimitiveField(env, javaField, javaObj, 'I', value); + SetPrimitiveField(env, javaField, javaObj, 'I', value, accessible); } -static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j) { +static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j, + jboolean accessible) { JValue value; value.SetJ(j); - SetPrimitiveField(env, javaField, javaObj, 'J', value); + SetPrimitiveField(env, javaField, javaObj, 'J', value, accessible); } -static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s) { +static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s, + jboolean accessible) { JValue value; value.SetS(s); - SetPrimitiveField(env, javaField, javaObj, 'S', value); + SetPrimitiveField(env, javaField, javaObj, 'S', value, accessible); } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Field, get, "!(Ljava/lang/Object;)Ljava/lang/Object;"), - NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;)Z"), - NATIVE_METHOD(Field, getByte, "!(Ljava/lang/Object;)B"), - NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;)C"), - NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;)D"), - NATIVE_METHOD(Field, getFloat, "!(Ljava/lang/Object;)F"), - NATIVE_METHOD(Field, getInt, "!(Ljava/lang/Object;)I"), - NATIVE_METHOD(Field, getLong, "!(Ljava/lang/Object;)J"), - NATIVE_METHOD(Field, getShort, "!(Ljava/lang/Object;)S"), - NATIVE_METHOD(Field, set, "!(Ljava/lang/Object;Ljava/lang/Object;)V"), - NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;Z)V"), - NATIVE_METHOD(Field, setByte, "!(Ljava/lang/Object;B)V"), - NATIVE_METHOD(Field, setChar, "!(Ljava/lang/Object;C)V"), - NATIVE_METHOD(Field, setDouble, "!(Ljava/lang/Object;D)V"), - NATIVE_METHOD(Field, setFloat, "!(Ljava/lang/Object;F)V"), - NATIVE_METHOD(Field, setInt, "!(Ljava/lang/Object;I)V"), - NATIVE_METHOD(Field, setLong, "!(Ljava/lang/Object;J)V"), - NATIVE_METHOD(Field, setShort, "!(Ljava/lang/Object;S)V"), + NATIVE_METHOD(Field, get, "!(Ljava/lang/Object;Z)Ljava/lang/Object;"), + NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;Z)Z"), + NATIVE_METHOD(Field, getByte, "!(Ljava/lang/Object;Z)B"), + NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;Z)C"), + NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;Z)D"), + NATIVE_METHOD(Field, getFloat, "!(Ljava/lang/Object;Z)F"), + NATIVE_METHOD(Field, getInt, "!(Ljava/lang/Object;Z)I"), + NATIVE_METHOD(Field, getLong, "!(Ljava/lang/Object;Z)J"), + NATIVE_METHOD(Field, getShort, "!(Ljava/lang/Object;Z)S"), + NATIVE_METHOD(Field, set, "!(Ljava/lang/Object;Ljava/lang/Object;Z)V"), + NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;ZZ)V"), + NATIVE_METHOD(Field, setByte, "!(Ljava/lang/Object;BZ)V"), + NATIVE_METHOD(Field, setChar, "!(Ljava/lang/Object;CZ)V"), + NATIVE_METHOD(Field, setDouble, "!(Ljava/lang/Object;DZ)V"), + NATIVE_METHOD(Field, setFloat, "!(Ljava/lang/Object;FZ)V"), + NATIVE_METHOD(Field, setInt, "!(Ljava/lang/Object;IZ)V"), + NATIVE_METHOD(Field, setLong, "!(Ljava/lang/Object;JZ)V"), + NATIVE_METHOD(Field, setShort, "!(Ljava/lang/Object;SZ)V"), }; void register_java_lang_reflect_Field(JNIEnv* env) { diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index abb73b6..c23f65c 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -29,10 +29,10 @@ namespace art { -static jobject Method_invoke(JNIEnv* env, - jobject javaMethod, jobject javaReceiver, jobject javaArgs) { +static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver, + jobject javaArgs, jboolean accessible) { ScopedFastNativeObjectAccess soa(env); - return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs); + return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, accessible); } static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) { @@ -56,7 +56,7 @@ static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) { } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"), + NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;Z)Ljava/lang/Object;"), NATIVE_METHOD(Method, getExceptionTypesNative, "!()[Ljava/lang/Class;"), }; diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 7f39e70..b38f9b4 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -26,6 +26,7 @@ #include "mirror/class-inl.h" #include "mirror/object_array.h" #include "mirror/object_array-inl.h" +#include "nth_caller_visitor.h" #include "object_utils.h" #include "scoped_thread_state_change.h" #include "stack.h" @@ -461,7 +462,7 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg } jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, - jobject javaReceiver, jobject javaArgs) { + jobject javaReceiver, jobject javaArgs, bool accessible) { mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod); mirror::Class* declaring_class = m->GetDeclaringClass(); @@ -499,6 +500,13 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, return NULL; } + // Validate access. + if (!accessible && !ValidateAccess(receiver, declaring_class, m->GetAccessFlags())) { + ThrowIllegalAccessException(nullptr, StringPrintf("Cannot access method: %s", + PrettyMethod(m).c_str()).c_str()); + return nullptr; + } + // Invoke the method. JValue result; ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); @@ -786,4 +794,30 @@ bool UnboxPrimitiveForResult(const ThrowLocation& throw_location, mirror::Object return UnboxPrimitive(&throw_location, o, dst_class, nullptr, unboxed_value); } +bool ValidateAccess(mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags) { + NthCallerVisitor visitor(Thread::Current(), 2); + visitor.WalkStack(); + mirror::Class* caller_class = visitor.caller->GetDeclaringClass(); + + if (((access_flags & kAccPublic) && declaring_class->IsPublic()) || + caller_class == declaring_class) { + return true; + } + if (access_flags & kAccPrivate) { + return false; + } + if (access_flags & kAccProtected) { + if (obj != nullptr && !obj->InstanceOf(caller_class) && + !declaring_class->IsInSamePackage(caller_class)) { + return false; + } else if (declaring_class->IsAssignableFrom(caller_class)) { + return true; + } + } + if (!declaring_class->IsInSamePackage(caller_class)) { + return false; + } + return true; +} + } // namespace art diff --git a/runtime/reflection.h b/runtime/reflection.h index 325998f..5cc725f 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -68,12 +68,15 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); jobject InvokeMethod(const ScopedObjectAccess& soa, jobject method, jobject receiver, - jobject args) + jobject args, bool accessible) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +bool ValidateAccess(mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + } // namespace art #endif // ART_RUNTIME_REFLECTION_H_ diff --git a/test/046-reflect/expected.txt b/test/046-reflect/expected.txt index fcfaf2f..55b0dbe 100644 --- a/test/046-reflect/expected.txt +++ b/test/046-reflect/expected.txt @@ -81,7 +81,8 @@ Field name is cantTouchThis Field type is int Access flags are 0x11 cantTouchThis is 77 - cantTouchThis is now 99 + as expected: set-final throws exception + cantTouchThis is still 77 public final int Target.cantTouchThis accessible=false public final int Target.cantTouchThis accessible=true cantTouchThis is now 87 diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java index dfb0d8f..d60fcb4 100644 --- a/test/046-reflect/src/Main.java +++ b/test/046-reflect/src/Main.java @@ -335,11 +335,12 @@ public class Main { System.out.println(" cantTouchThis is " + intVal); try { field.setInt(instance, 99); + System.out.println("ERROR: set-final did not throw exception"); } catch (IllegalAccessException iae) { - System.out.println("ERROR: set-final failed"); + System.out.println(" as expected: set-final throws exception"); } intVal = field.getInt(instance); - System.out.println(" cantTouchThis is now " + intVal); + System.out.println(" cantTouchThis is still " + intVal); System.out.println(" " + field + " accessible=" + field.isAccessible()); field.setAccessible(true); diff --git a/test/064-field-access/src/Main.java b/test/064-field-access/src/Main.java index 3b9a475..c9b93ba 100644 --- a/test/064-field-access/src/Main.java +++ b/test/064-field-access/src/Main.java @@ -16,6 +16,7 @@ import other.PublicClass; import java.lang.reflect.Field; +import java.lang.reflect.Method; /* * Test field access through reflection. @@ -192,6 +193,11 @@ class SamePackage { /* package */ static float samePackagePackageFloatStaticField = 63.0f; /* package */ static double samePackagePackageDoubleStaticField = 64.0; /* package */ static Object samePackagePackageObjectStaticField = "65"; + + public void samePublicMethod() { } + protected void sameProtectedMethod() { } + private void samePrivateMethod() { } + /* package */ void samePackageMethod() { } } /* @@ -510,23 +516,32 @@ class SubClass extends PublicClass { for (int round = 0; round < 3; round++) { Object validInst; Field[] fields; + Method[] methods; boolean same_package = false; + boolean protected_class = false; switch (round) { case 0: validInst = new SamePackage(); fields = SamePackage.class.getDeclaredFields(); check(fields.length == 72); + methods = SamePackage.class.getDeclaredMethods(); + check(methods.length == 4); same_package = true; break; case 1: validInst = new PublicClass(); fields = PublicClass.class.getDeclaredFields(); check(fields.length == 72); + methods = PublicClass.class.getDeclaredMethods(); + check(methods.length == 4); break; default: validInst = new PublicClass(); fields = PublicClass.class.getSuperclass().getDeclaredFields(); check(fields.length == 72); + methods = PublicClass.class.getSuperclass().getDeclaredMethods(); + check(methods.length == 4); + protected_class = true; break; } for (Field f : fields) { @@ -540,16 +555,15 @@ class SubClass extends PublicClass { // Check access or lack of to field. Class<?> subClassAccessExceptionClass = null; if (f.getName().contains("Private") || - (!same_package && f.getName().contains("Package"))) { - // ART deliberately doesn't throw IllegalAccessException. - // subClassAccessExceptionClass = IllegalAccessException.class; + (!same_package && f.getName().contains("Package")) || + (!same_package && f.getName().contains("Protected"))) { + subClassAccessExceptionClass = IllegalAccessException.class; } Class<?> mainClassAccessExceptionClass = null; if (f.getName().contains("Private") || (!same_package && f.getName().contains("Package")) || (!same_package && f.getName().contains("Protected"))) { - // ART deliberately doesn't throw IllegalAccessException. - // mainClassAccessExceptionClass = IllegalAccessException.class; + mainClassAccessExceptionClass = IllegalAccessException.class; } this.getValue(f, validInst, typeChar, subClassAccessExceptionClass); @@ -588,6 +602,16 @@ class SubClass extends PublicClass { } } } + + for (Method m : methods) { + Class<?> subClassAccessExceptionClass = null; + if (protected_class || m.getName().contains("Private") || + (!same_package && m.getName().contains("Package")) || + (!same_package && m.getName().contains("Protected"))) { + subClassAccessExceptionClass = IllegalAccessException.class; + } + this.invoke(m, validInst, subClassAccessExceptionClass); + } } System.out.println("good"); } @@ -598,7 +622,6 @@ class SubClass extends PublicClass { */ public Object getValue(Field field, Object obj, char type, Class expectedException) { - Object result = null; try { switch (type) { @@ -657,4 +680,29 @@ class SubClass extends PublicClass { return result; } + + public Object invoke(Method method, Object obj, Class expectedException) { + Object result = null; + try { + result = method.invoke(obj); + /* success; expected? */ + if (expectedException != null) { + System.err.println("ERROR: call succeeded for method " + method + "', was expecting " + + expectedException); + Thread.dumpStack(); + } + } catch (Exception ex) { + if (expectedException == null) { + System.err.println("ERROR: call failed unexpectedly: " + ex.getClass()); + ex.printStackTrace(); + } else { + if (!expectedException.equals(ex.getClass())) { + System.err.println("ERROR: incorrect exception: wanted " + expectedException.getName() + + ", got " + ex.getClass()); + ex.printStackTrace(); + } + } + } + return result; + } } diff --git a/test/064-field-access/src/other/ProtectedClass.java b/test/064-field-access/src/other/ProtectedClass.java index 779aa1d..756c97f 100644 --- a/test/064-field-access/src/other/ProtectedClass.java +++ b/test/064-field-access/src/other/ProtectedClass.java @@ -97,4 +97,10 @@ class ProtectedClass { /* package */ static float otherProtectedClassPackageFloatStaticField = 63.0f; /* package */ static double otherProtectedClassPackageDoubleStaticField = 64.0; /* package */ static Object otherProtectedClassPackageObjectStaticField = "65"; + + public void otherPublicMethod() { } + protected void otherProtectedMethod() { } + private void otherPrivateMethod() { } + /* package */ void otherPackageMethod() { } + } diff --git a/test/064-field-access/src/other/PublicClass.java b/test/064-field-access/src/other/PublicClass.java index 1653973..dbcb4fd 100644 --- a/test/064-field-access/src/other/PublicClass.java +++ b/test/064-field-access/src/other/PublicClass.java @@ -97,4 +97,9 @@ public class PublicClass extends ProtectedClass { /* package */ static float otherPublicClassPackageFloatStaticField = -63.0f; /* package */ static double otherPublicClassPackageDoubleStaticField = -64.0; /* package */ static Object otherPublicClassPackageObjectStaticField = "-65"; + + public void otherPublicMethod() { } + protected void otherProtectedMethod() { } + private void otherPrivateMethod() { } + /* package */ void otherPackageMethod() { } } diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 3d87ebc..bed0689 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -22,10 +22,7 @@ z 30 62 14 -java.lang.IllegalArgumentException: Invalid primitive conversion from int to short - at java.lang.reflect.Field.set(Native Method) - at Main.testFieldReflection(Main.java:121) - at Main.main(Main.java:269) +got expected IllegalArgumentException true (class java.lang.Boolean) 6 (class java.lang.Byte) z (class java.lang.Character) @@ -66,12 +63,6 @@ null (null) true 0 1 2.0 hello world 3.0 4 5 6 null (null) [] -java.lang.reflect.InvocationTargetException - at java.lang.reflect.Method.invoke(Native Method) - at Main.testMethodReflection(Main.java:210) - at Main.main(Main.java:270) -Caused by: java.lang.ArithmeticException: surprise! - at Main.thrower(Main.java:218) - ... 3 more +got expected InvocationTargetException (class java.lang.String) yz (class java.lang.String) diff --git a/test/100-reflect2/src/Main.java b/test/100-reflect2/src/Main.java index 0404591..0cc1488 100644 --- a/test/100-reflect2/src/Main.java +++ b/test/100-reflect2/src/Main.java @@ -119,8 +119,9 @@ class Main { try { f = Main.class.getDeclaredField("s"); f.set(null, Integer.valueOf(14)); + System.out.println("************* should have thrown!"); } catch (IllegalArgumentException expected) { - expected.printStackTrace(); + System.out.println("got expected IllegalArgumentException"); } f = Main.class.getDeclaredField("z"); @@ -209,8 +210,8 @@ class Main { System.out.println(Arrays.toString(m.getParameterTypes())); show(m.invoke(null)); System.out.println("************* should have thrown!"); - } catch (Exception expected) { - expected.printStackTrace(); + } catch (InvocationTargetException expected) { + System.out.println("got expected InvocationTargetException"); } } |