Ensure that overrides work in presence of package-private methods.
It was possible that methods with the same signature & name of
package-private methods could fail to be correctly overridden causing
surprising behavior and DCHECK failures.
Bug: 32193118
Test: mma test-art-host
Test: ART_TEST_RUN_TEST_NDEBUG=true ART_TEST_RUN_TEST_NO_PREBUILD=true mma test-art-host-run-test-300-package-override
Change-Id: I8f53a830cd8d4210f60e9827e525c779a0696e04
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index a7d8b13..cea8377 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5643,27 +5643,29 @@
for (size_t j = 0; j < super_vtable_length; ++j) {
// Search the hash table to see if we are overridden by any method.
ArtMethod* super_method = vtable->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_);
+ if (!klass->CanAccessMember(super_method->GetDeclaringClass(),
+ super_method->GetAccessFlags())) {
+ // Continue on to the next method since this one is package private and canot be overridden.
+ // Before Android 4.1, the package-private method super_method might have been incorrectly
+ // overridden.
+ continue;
+ }
MethodNameAndSignatureComparator super_method_name_comparator(
super_method->GetInterfaceMethodIfProxy(image_pointer_size_));
+ // We remove the method so that subsequent lookups will be faster by making the hash-map
+ // smaller as we go on.
uint32_t hash_index = hash_table.FindAndRemove(&super_method_name_comparator);
if (hash_index != hash_table.GetNotFoundIndex()) {
ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(
hash_index, image_pointer_size_);
- if (klass->CanAccessMember(super_method->GetDeclaringClass(),
- super_method->GetAccessFlags())) {
- if (super_method->IsFinal()) {
- ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
- ArtMethod::PrettyMethod(virtual_method).c_str(),
- super_method->GetDeclaringClassDescriptor());
- return false;
- }
- vtable->SetElementPtrSize(j, virtual_method, image_pointer_size_);
- virtual_method->SetMethodIndex(j);
- } else {
- LOG(WARNING) << "Before Android 4.1, method " << ArtMethod::PrettyMethod(virtual_method)
- << " would have incorrectly overridden the package-private method in "
- << PrettyDescriptor(super_method->GetDeclaringClassDescriptor());
+ if (super_method->IsFinal()) {
+ ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
+ virtual_method->PrettyMethod().c_str(),
+ super_method->GetDeclaringClassDescriptor());
+ return false;
}
+ vtable->SetElementPtrSize(j, virtual_method, image_pointer_size_);
+ virtual_method->SetMethodIndex(j);
} else if (super_method->IsOverridableByDefaultMethod()) {
// We didn't directly override this method but we might through default methods...
// Check for default method update.
@@ -6458,15 +6460,20 @@
}
MethodNameAndSignatureComparator name_comparator(
vtable_entry->GetInterfaceMethodIfProxy(pointer_size));
- for (int32_t j = i+1; j < num_entries; j++) {
+ for (int32_t j = i + 1; j < num_entries; j++) {
ArtMethod* other_entry = vtable->GetElementPtrSize<ArtMethod*>(j, pointer_size);
+ if (!klass->CanAccessMember(other_entry->GetDeclaringClass(),
+ other_entry->GetAccessFlags())) {
+ continue;
+ }
CHECK(vtable_entry != other_entry &&
!name_comparator.HasSameNameAndSignature(
other_entry->GetInterfaceMethodIfProxy(pointer_size)))
<< "vtable entries " << i << " and " << j << " are identical for "
- << klass->PrettyClass() << " in method "
- << vtable_entry->PrettyMethod()
- << " and " << other_entry->PrettyMethod();
+ << klass->PrettyClass() << " in method " << vtable_entry->PrettyMethod() << " (0x"
+ << std::hex << reinterpret_cast<uintptr_t>(vtable_entry) << ") and "
+ << other_entry->PrettyMethod() << " (0x" << std::hex
+ << reinterpret_cast<uintptr_t>(other_entry) << ")";
}
}
}