diff options
| -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 24d16c4c97..4b6d82b35b 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 792cdefce2..c06763e4b4 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 b7e8ac273a..d28ebd0e78 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 48b58bf807..755708ebf6 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 abb73b6927..c23f65cae6 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 7f39e70b8e..b38f9b42a2 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 325998fe20..5cc725f2c6 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 fcfaf2ff3f..55b0dbe8f4 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 dfb0d8fe9b..d60fcb485b 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 3b9a4758db..c9b93ba846 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 779aa1d09d..756c97f15a 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 1653973d5d..dbcb4fd902 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 3d87ebc559..bed0689e82 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 04045912a4..0cc1488122 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");      }    }  |