diff options
Diffstat (limited to 'runtime')
-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 |
6 files changed, 90 insertions, 44 deletions
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_); |