Fix bug in protected field access.
Change-Id: I38b094e54025d26950c0d8c8bb79d2de81d28428
diff --git a/src/compiler.cc b/src/compiler.cc
index 3980bac..7369535 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -628,17 +628,31 @@
Field* resolved_field = ComputeReferrerField(mUnit, field_idx);
if (resolved_field != NULL) {
Class* referrer_class = ComputeReferrerClass(mUnit);
- // Try to resolve referring class then access check, failure to pass the
- Class* fields_class = resolved_field->GetDeclaringClass();
- bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() &&
- fields_class != referrer_class;
- if (referrer_class != NULL && referrer_class->CanAccess(fields_class) &&
- referrer_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) &&
- !is_write_to_final_from_wrong_class) {
- field_offset = resolved_field->GetOffset().Int32Value();
- is_volatile = resolved_field->IsVolatile();
- stats_->ResolvedInstanceField();
- return true; // Fast path.
+ if (referrer_class != NULL) {
+ 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 = mUnit->class_linker_->FindDexFile(referrer_class->GetDexCache());
+ Class* dex_fields_class = mUnit->class_linker_->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 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) {
+ field_offset = resolved_field->GetOffset().Int32Value();
+ is_volatile = resolved_field->IsVolatile();
+ stats_->ResolvedInstanceField();
+ return true; // Fast path.
+ }
}
}
// Clean up any exception left by field/type resolution
@@ -672,10 +686,25 @@
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 = mUnit->class_linker_->FindDexFile(referrer_class->GetDexCache());
+ Class* dex_fields_class =
+ mUnit->class_linker_->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 is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal();
- if (referrer_class->CanAccess(fields_class) &&
- referrer_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) &&
- !is_write_to_final_from_wrong_class) {
+ if (access_ok && !is_write_to_final_from_wrong_class) {
// We have the resolved field, we must make it into a ssbIndex for the referrer
// in its static storage base (which may fail if it doesn't have a slot for it)
// TODO: for images we can elide the static storage base null check
@@ -689,7 +718,8 @@
stats_->ResolvedStaticField();
return true;
}
- // Search dex file for localized ssb index
+ // Search dex file for localized ssb index, may fail if field's class is a parent
+ // of the class mentioned in the dex file and there is no dex cache entry.
std::string descriptor(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
const DexFile::StringId* string_id =
mUnit->dex_file_->FindStringId(descriptor);
diff --git a/src/oat/runtime/support_dexcache.cc b/src/oat/runtime/support_dexcache.cc
index e5f2f82..49e038d 100644
--- a/src/oat/runtime/support_dexcache.cc
+++ b/src/oat/runtime/support_dexcache.cc
@@ -21,13 +21,16 @@
extern "C" Class* artInitializeStaticStorageFromCode(uint32_t type_idx, const Method* referrer,
Thread* self, Method** sp) {
+ // Called to ensure static storage base is initialized for direct static field reads and writes.
+ // A class may be accessing another class' fields when it doesn't have access, as access has been
+ // given by inheritance.
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return ResolveVerifyAndClinit(type_idx, referrer, self, true, true);
+ return ResolveVerifyAndClinit(type_idx, referrer, self, true, false);
}
extern "C" Class* artInitializeTypeFromCode(uint32_t type_idx, const Method* referrer, Thread* self,
Method** sp) {
- // Called when method->dex_cache_resolved_types_[] misses
+ // Called when method->dex_cache_resolved_types_[] misses.
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
return ResolveVerifyAndClinit(type_idx, referrer, self, false, false);
}
@@ -36,7 +39,7 @@
const Method* referrer, Thread* self,
Method** sp) {
// Called when caller isn't guaranteed to have access to a type and the dex cache may be
- // unpopulated
+ // unpopulated.
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
return ResolveVerifyAndClinit(type_idx, referrer, self, false, true);
}
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 38a680e..8c2b30c 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -357,14 +357,26 @@
} else {
Class* fields_class = resolved_field->GetDeclaringClass();
Class* referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
- ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
- return NULL; // failure
- } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags()))) {
- ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
- return NULL; // failure
- } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
+ 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 = class_linker->FindDexFile(referring_class->GetDexCache());
+ fields_class = class_linker->ResolveType(dex_file,
+ dex_file.GetFieldId(field_idx).class_idx_,
+ referring_class);
+ if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
+ ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
+ return NULL; // failure
+ } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
+ resolved_field->GetAccessFlags()))) {
+ ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
+ return NULL; // failure
+ }
+ }
+ if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
return NULL; // failure
} else {