Don't assume resolved type has the same dex cache.
When we resolve a type with a certain DexCache that type's
GetDexCache() doesn't necessarily return the same DexCache.
This could have led to the wrong DexFile being used in
access checks by the CompilerDriver.
Change-Id: I2c836477f69f142bcbff902207dc0ad83854a398
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index f6e8ca3..a95fe12 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -311,8 +311,8 @@
return nullptr;
}
mirror::Class* referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccessResolvedField<true>(fields_class, resolved_field,
- field_idx))) {
+ if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field,
+ field_idx))) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
return nullptr; // Failure.
}
@@ -402,8 +402,8 @@
mirror::Class* methods_class = resolved_method->GetDeclaringClass();
mirror::Class* referring_class = referrer->GetDeclaringClass();
bool can_access_resolved_method =
- referring_class->CanAccessResolvedMethod<true, type>(methods_class, resolved_method,
- method_idx);
+ referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
+ method_idx);
if (UNLIKELY(!can_access_resolved_method)) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
return nullptr; // Failure.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index cd44ebc..8aa8333 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -203,14 +203,15 @@
return IsArrayAssignableFromArray(src);
}
-template <bool throw_on_failure>
-inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field,
- uint32_t field_idx) {
+template <bool throw_on_failure, bool use_referrers_cache>
+inline bool Class::ResolvedFieldAccessTest(Class* access_to, ArtField* field,
+ uint32_t field_idx, DexCache* dex_cache) {
+ DCHECK_EQ(use_referrers_cache, dex_cache == nullptr);
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();
+ DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
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);
@@ -233,15 +234,16 @@
return false;
}
-template <bool throw_on_failure, InvokeType throw_invoke_type>
-inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method,
- uint32_t method_idx) {
+template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type>
+inline bool Class::ResolvedMethodAccessTest(Class* access_to, ArtMethod* method,
+ uint32_t method_idx, DexCache* dex_cache) {
COMPILE_ASSERT(throw_on_failure || throw_invoke_type == kStatic, non_default_throw_invoke_type);
+ DCHECK_EQ(use_referrers_cache, dex_cache == nullptr);
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();
+ DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
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);
@@ -265,6 +267,28 @@
return false;
}
+inline bool Class::CanAccessResolvedField(Class* access_to, ArtField* field,
+ DexCache& dex_cache, uint32_t field_idx) {
+ return ResolvedFieldAccessTest<false, false>(access_to, field, field_idx, &dex_cache);
+}
+
+inline bool Class::CheckResolvedFieldAccess(Class* access_to, ArtField* field,
+ uint32_t field_idx) {
+ return ResolvedFieldAccessTest<true, true>(access_to, field, field_idx, nullptr);
+}
+
+inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method,
+ DexCache& dex_cache, uint32_t method_idx) {
+ return ResolvedMethodAccessTest<false, false, kStatic>(access_to, method, method_idx, &dex_cache);
+}
+
+template <InvokeType throw_invoke_type>
+inline bool Class::CheckResolvedMethodAccess(Class* access_to, ArtMethod* method,
+ uint32_t method_idx) {
+ return ResolvedMethodAccessTest<true, true, throw_invoke_type>(access_to, method, method_idx,
+ nullptr);
+}
+
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 d751363..8071d79 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -453,16 +453,23 @@
// 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_);
+ DexCache& dex_cache, uint32_t field_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool CheckResolvedFieldAccess(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_);
+ DexCache& dex_cache, uint32_t method_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template <InvokeType throw_invoke_type>
+ bool CheckResolvedMethodAccess(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_);
@@ -808,6 +815,15 @@
private:
void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template <bool throw_on_failure, bool use_referrers_cache>
+ bool ResolvedFieldAccessTest(Class* access_to, ArtField* field,
+ uint32_t field_idx, DexCache* dex_cache)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template <bool throw_on_failure, bool use_referrers_cache, InvokeType throw_invoke_type>
+ bool ResolvedMethodAccessTest(Class* access_to, ArtMethod* resolved_method,
+ uint32_t method_idx, DexCache* dex_cache)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
bool Implements(const Class* klass) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsArrayAssignableFromArray(const Class* klass) const