diff options
author | Vladimir Marko <vmarko@google.com> | 2014-01-09 19:24:37 +0000 |
---|---|---|
committer | Vladimir Marko <vmarko@google.com> | 2014-01-21 17:09:51 +0000 |
commit | 23a282146042a0d171aec2a415176f5d0621a90c (patch) | |
tree | de676891deb5bee6bc76b7cba23c29df662e57c0 | |
parent | d6c3ae638a47db3970054843d2aa2f0d961cec4c (diff) | |
download | android_art-23a282146042a0d171aec2a415176f5d0621a90c.tar.gz android_art-23a282146042a0d171aec2a415176f5d0621a90c.tar.bz2 android_art-23a282146042a0d171aec2a415176f5d0621a90c.zip |
Clean up access checks.
Change-Id: Ia62ba6c8f1d0a9bfbbfde2d7be4c52c0f982b9d2
-rw-r--r-- | compiler/driver/compiler_driver.cc | 52 | ||||
-rw-r--r-- | runtime/class_linker.cc | 2 | ||||
-rw-r--r-- | runtime/common_throws.cc | 1 | ||||
-rw-r--r-- | runtime/common_throws.h | 1 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.h | 52 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 63 | ||||
-rw-r--r-- | runtime/mirror/class.h | 15 |
7 files changed, 96 insertions, 90 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 5edc8b6771..f713151dc5 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -958,21 +958,8 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi ComputeCompilingMethodsClass(soa, dex_cache, mUnit); if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); - bool access_ok = referrer_class->CanAccess(fields_class) && - referrer_class->CanAccessMember(fields_class, - resolved_field->GetAccessFlags()); - if (!access_ok) { - // The referring class can't access the resolved field, this may occur as a result of a - // protected field being made public by a sub-class. Resort to the dex file to determine - // the correct class for the access check. - const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile(); - mirror::Class* dex_fields_class = mUnit->GetClassLinker()->ResolveType(dex_file, - dex_file.GetFieldId(field_idx).class_idx_, - referrer_class); - access_ok = referrer_class->CanAccess(dex_fields_class) && - referrer_class->CanAccessMember(dex_fields_class, - resolved_field->GetAccessFlags()); - } + bool access_ok = + referrer_class->CanAccessResolvedField<false>(fields_class, resolved_field, field_idx); bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() && fields_class != referrer_class; if (access_ok && !is_write_to_final_from_wrong_class) { @@ -1018,23 +1005,8 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila stats_->ResolvedLocalStaticField(); return true; // fast path } else { - bool access_ok = referrer_class->CanAccess(fields_class) && - referrer_class->CanAccessMember(fields_class, - resolved_field->GetAccessFlags()); - if (!access_ok) { - // The referring class can't access the resolved field, this may occur as a result of a - // protected field being made public by a sub-class. Resort to the dex file to determine - // the correct class for the access check. Don't change the field's class as that is - // used to identify the SSB. - const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile(); - mirror::Class* dex_fields_class = - mUnit->GetClassLinker()->ResolveType(dex_file, - dex_file.GetFieldId(field_idx).class_idx_, - referrer_class); - access_ok = referrer_class->CanAccess(dex_fields_class) && - referrer_class->CanAccessMember(dex_fields_class, - resolved_field->GetAccessFlags()); - } + bool access_ok = + referrer_class->CanAccessResolvedField<false>(fields_class, resolved_field, field_idx); bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal(); if (access_ok && !is_write_to_final_from_wrong_class) { // We have the resolved field, we must make it into a index for the referrer @@ -1217,20 +1189,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); - if (!referrer_class->CanAccess(methods_class) || - !referrer_class->CanAccessMember(methods_class, - resolved_method->GetAccessFlags())) { - // The referring class can't access the resolved method, this may occur as a result of a - // protected method being made public by implementing an interface that re-declares the - // method public. Resort to the dex file to determine the correct class for the access - // check. - uint16_t class_idx = - target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_; - methods_class = mUnit->GetClassLinker()->ResolveType(*target_method->dex_file, - class_idx, referrer_class); - } - if (referrer_class->CanAccess(methods_class) && - referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) { + if (referrer_class->CanAccessResolvedMethod<false>(methods_class, resolved_method, + target_method->dex_method_index)) { const bool enableFinalBasedSharpening = enable_devirtualization; // Sharpen a virtual call into a direct call when the target is known not to have been // overridden (ie is final). diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b1117a27db..b5d9fdfbd9 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4186,7 +4186,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, mirror::Class* referring_class = referrer->GetDeclaringClass(); if (!referring_class->CanAccess(methods_class)) { ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class, - referrer, resolved, type); + resolved, type); return NULL; } else if (!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags())) { diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 0419dab0f8..dd832df373 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -136,7 +136,6 @@ void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* access } void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed, - const mirror::ArtMethod* caller, const mirror::ArtMethod* called, InvokeType type) { std::ostringstream msg; diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 3164f308c1..7f13891400 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -76,7 +76,6 @@ void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* access SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed, - const mirror::ArtMethod* caller, const mirror::ArtMethod* called, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR; diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 830422946e..09be56e8a4 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -226,28 +226,14 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr return nullptr; } mirror::Class* referring_class = referrer->GetDeclaringClass(); - if (UNLIKELY(!referring_class->CanAccess(fields_class) || - !referring_class->CanAccessMember(fields_class, - resolved_field->GetAccessFlags()))) { - // The referring class can't access the resolved field, this may occur as a result of a - // protected field being made public by a sub-class. Resort to the dex file to determine - // the correct class for the access check. - const DexFile& dex_file = *referring_class->GetDexCache()->GetDexFile(); - fields_class = class_linker->ResolveType(dex_file, - dex_file.GetFieldId(field_idx).class_idx_, - referring_class); - if (UNLIKELY(!referring_class->CanAccess(fields_class))) { - ThrowIllegalAccessErrorClass(referring_class, fields_class); - return nullptr; // failure - } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class, - resolved_field->GetAccessFlags()))) { - ThrowIllegalAccessErrorField(referring_class, resolved_field); - return nullptr; // failure - } + if (UNLIKELY(!referring_class->CanAccessResolvedField<true>(fields_class, resolved_field, + field_idx))) { + DCHECK(self->IsExceptionPending()); // Throw exception and unwind. + return nullptr; // Failure. } if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) { ThrowIllegalAccessErrorFinalField(referrer, resolved_field); - return nullptr; // failure + return nullptr; // Failure. } else { FieldHelper fh(resolved_field); if (UNLIKELY(fh.IsPrimitiveType() != is_primitive || @@ -259,7 +245,7 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr expected_size * (32 / sizeof(int32_t)), is_primitive ? "primitive" : "non-primitive", PrettyField(resolved_field, true).c_str()); - return nullptr; // failure + return nullptr; // Failure. } } } @@ -277,7 +263,7 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr return resolved_field; } else { DCHECK(self->IsExceptionPending()); // Throw exception and unwind - return nullptr; // failure + return nullptr; // Failure. } } } @@ -330,26 +316,10 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror: } mirror::Class* methods_class = resolved_method->GetDeclaringClass(); mirror::Class* referring_class = referrer->GetDeclaringClass(); - if (UNLIKELY(!referring_class->CanAccess(methods_class) || - !referring_class->CanAccessMember(methods_class, - resolved_method->GetAccessFlags()))) { - // The referring class can't access the resolved method, this may occur as a result of a - // protected method being made public by implementing an interface that re-declares the - // method public. Resort to the dex file to determine the correct class for the access check - const DexFile& dex_file = *referring_class->GetDexCache()->GetDexFile(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - methods_class = class_linker->ResolveType(dex_file, - dex_file.GetMethodId(method_idx).class_idx_, - referring_class); - if (UNLIKELY(!referring_class->CanAccess(methods_class))) { - ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class, - referrer, resolved_method, type); - return nullptr; // Failure. - } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class, - resolved_method->GetAccessFlags()))) { - ThrowIllegalAccessErrorMethod(referring_class, resolved_method); - return nullptr; // Failure. - } + if (!referring_class->CanAccessResolvedMethod<true, type>(methods_class, resolved_method, + method_idx)) { + DCHECK(self->IsExceptionPending()); // Throw exception and unwind. + return nullptr; // Failure. } } switch (type) { diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index e0fab8ce56..cd44ebcb65 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -22,6 +22,7 @@ #include "art_field.h" #include "art_method.h" #include "class_loader.h" +#include "common_throws.h" #include "dex_cache.h" #include "gc/heap-inl.h" #include "iftable.h" @@ -202,6 +203,68 @@ inline bool Class::IsAssignableFromArray(const Class* src) const { return IsArrayAssignableFromArray(src); } +template <bool throw_on_failure> +inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field, + uint32_t field_idx) { + if (UNLIKELY(!this->CanAccess(access_to))) { + // The referrer class can't access the field's declaring class but may still be able + // to access the field if the FieldId specifies an accessible subclass of the declaring + // class rather than the declaring class itself. + DexCache* referrer_dex_cache = this->GetDexCache(); + uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_; + // The referenced class has already been resolved with the field, get it from the dex cache. + Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx); + DCHECK(dex_access_to != nullptr); + if (UNLIKELY(!this->CanAccess(dex_access_to))) { + if (throw_on_failure) { + ThrowIllegalAccessErrorClass(this, dex_access_to); + } + return false; + } + DCHECK_EQ(this->CanAccessMember(access_to, field->GetAccessFlags()), + this->CanAccessMember(dex_access_to, field->GetAccessFlags())); + } + if (LIKELY(this->CanAccessMember(access_to, field->GetAccessFlags()))) { + return true; + } + if (throw_on_failure) { + ThrowIllegalAccessErrorField(this, field); + } + return false; +} + +template <bool throw_on_failure, InvokeType throw_invoke_type> +inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method, + uint32_t method_idx) { + COMPILE_ASSERT(throw_on_failure || throw_invoke_type == kStatic, non_default_throw_invoke_type); + if (UNLIKELY(!this->CanAccess(access_to))) { + // The referrer class can't access the method's declaring class but may still be able + // to access the method if the MethodId specifies an accessible subclass of the declaring + // class rather than the declaring class itself. + DexCache* referrer_dex_cache = this->GetDexCache(); + uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_; + // The referenced class has already been resolved with the method, get it from the dex cache. + Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx); + DCHECK(dex_access_to != nullptr); + if (UNLIKELY(!this->CanAccess(dex_access_to))) { + if (throw_on_failure) { + ThrowIllegalAccessErrorClassForMethodDispatch(this, dex_access_to, + method, throw_invoke_type); + } + return false; + } + DCHECK_EQ(this->CanAccessMember(access_to, method->GetAccessFlags()), + this->CanAccessMember(dex_access_to, method->GetAccessFlags())); + } + if (LIKELY(this->CanAccessMember(access_to, method->GetAccessFlags()))) { + return true; + } + if (throw_on_failure) { + ThrowIllegalAccessErrorMethod(this, method); + } + return false; +} + inline bool Class::IsSubClass(const Class* klass) const { DCHECK(!IsInterface()) << PrettyClass(this); DCHECK(!IsArrayClass()) << PrettyClass(this); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 9aa23d91d3..d751363e3f 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_MIRROR_CLASS_H_ #include "gc/heap.h" +#include "invoke_type.h" #include "modifiers.h" #include "object.h" #include "primitive.h" @@ -449,6 +450,20 @@ class MANAGED Class : public Object { return this->IsInSamePackage(access_to); } + // Can this class access a resolved field? + // Note that access to field's class is checked and this may require looking up the class + // referenced by the FieldId in the DexFile in case the declaring class is inaccessible. + template <bool throw_on_failure> + bool CanAccessResolvedField(Class* access_to, ArtField* field, + uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Can this class access a resolved method? + // Note that access to methods's class is checked and this may require looking up the class + // referenced by the MethodId in the DexFile in case the declaring class is inaccessible. + template <bool throw_on_failure, InvokeType throw_invoke_type = kStatic> + bool CanAccessResolvedMethod(Class* access_to, ArtMethod* resolved_method, + uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsSubClass(const Class* klass) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |