ART: Add more details to LinkageError
Add the classes or method details that fail during linking to enable
better diagnosis of problems.
Bug: 19294695
Change-Id: Ifab48bc182cd801d44d3aead2168028f27043be0
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 25750bb..3592d2c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4293,7 +4293,8 @@
static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
Handle<mirror::ArtMethod> method1,
- Handle<mirror::ArtMethod> method2)
+ Handle<mirror::ArtMethod> method2,
+ std::string* error_msg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
{
StackHandleScope<1> hs(self);
@@ -4301,18 +4302,35 @@
mirror::Class* other_return_type = method2->GetReturnType();
// NOTE: return_type.Get() must be sequenced after method2->GetReturnType().
if (UNLIKELY(other_return_type != return_type.Get())) {
+ *error_msg = StringPrintf("Return types mismatch: %s(%p) vs %s(%p)",
+ PrettyClassAndClassLoader(return_type.Get()).c_str(),
+ return_type.Get(),
+ PrettyClassAndClassLoader(other_return_type).c_str(),
+ other_return_type);
return false;
}
}
const DexFile::TypeList* types1 = method1->GetParameterTypeList();
const DexFile::TypeList* types2 = method2->GetParameterTypeList();
if (types1 == nullptr) {
- return (types2 == nullptr) || (types2->Size() == 0);
+ if (types2 != nullptr && types2->Size() != 0) {
+ *error_msg = StringPrintf("Type list mismatch with %s",
+ PrettyMethod(method2.Get(), true).c_str());
+ return false;
+ }
+ return true;
} else if (UNLIKELY(types2 == nullptr)) {
- return types1->Size() == 0;
+ if (types1->Size() != 0) {
+ *error_msg = StringPrintf("Type list mismatch with %s",
+ PrettyMethod(method2.Get(), true).c_str());
+ return false;
+ }
+ return true;
}
uint32_t num_types = types1->Size();
if (UNLIKELY(num_types != types2->Size())) {
+ *error_msg = StringPrintf("Type list mismatch with %s",
+ PrettyMethod(method2.Get(), true).c_str());
return false;
}
for (uint32_t i = 0; i < num_types; ++i) {
@@ -4323,6 +4341,12 @@
method2->GetClassFromTypeIndex(types2->GetTypeItem(i).type_idx_, true);
// NOTE: param_type.Get() must be sequenced after method2->GetClassFromTypeIndex(...).
if (UNLIKELY(param_type.Get() != other_param_type)) {
+ *error_msg = StringPrintf("Parameter %u type mismatch: %s(%p) vs %s(%p)",
+ i,
+ PrettyClassAndClassLoader(param_type.Get()).c_str(),
+ param_type.Get(),
+ PrettyClassAndClassLoader(other_param_type).c_str(),
+ other_param_type);
return false;
}
}
@@ -4344,14 +4368,17 @@
for (int i = klass->GetSuperClass()->GetVTableLength() - 1; i >= 0; --i) {
h_m.Assign(klass->GetVTableEntry(i));
super_h_m.Assign(klass->GetSuperClass()->GetVTableEntry(i));
- if (h_m.Get() != super_h_m.Get() &&
- !HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m)) {
- ThrowLinkageError(klass.Get(),
- "Class %s method %s resolves differently in superclass %s",
- PrettyDescriptor(klass.Get()).c_str(),
- PrettyMethod(h_m.Get()).c_str(),
- PrettyDescriptor(klass->GetSuperClass()).c_str());
- return false;
+ if (h_m.Get() != super_h_m.Get()) {
+ std::string error_msg;
+ if (!HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m, &error_msg)) {
+ ThrowLinkageError(klass.Get(),
+ "Class %s method %s resolves differently in superclass %s: %s",
+ PrettyDescriptor(klass.Get()).c_str(),
+ PrettyMethod(h_m.Get()).c_str(),
+ PrettyDescriptor(klass->GetSuperClass()).c_str(),
+ error_msg.c_str());
+ return false;
+ }
}
}
}
@@ -4361,14 +4388,17 @@
for (uint32_t j = 0; j < num_methods; ++j) {
h_m.Assign(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j));
super_h_m.Assign(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
- if (h_m.Get() != super_h_m.Get() &&
- !HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m)) {
- ThrowLinkageError(klass.Get(),
- "Class %s method %s resolves differently in interface %s",
- PrettyDescriptor(klass.Get()).c_str(),
- PrettyMethod(h_m.Get()).c_str(),
- PrettyDescriptor(klass->GetIfTable()->GetInterface(i)).c_str());
- return false;
+ if (h_m.Get() != super_h_m.Get()) {
+ std::string error_msg;
+ if (!HasSameSignatureWithDifferentClassLoaders(self, h_m, super_h_m, &error_msg)) {
+ ThrowLinkageError(klass.Get(),
+ "Class %s method %s resolves differently in interface %s: %s",
+ PrettyDescriptor(klass.Get()).c_str(),
+ PrettyMethod(h_m.Get()).c_str(),
+ PrettyDescriptor(klass->GetIfTable()->GetInterface(i)).c_str(),
+ error_msg.c_str());
+ return false;
+ }
}
}
}