Fix double-exception in super-class method validation.

Bug: 19333589

(cherry picked from commit d5e5a0e61b5b1fe0aaa7edc25a08adebd5a92353)

Change-Id: If394a678ef6271c1119dac3f959773f23e789c56
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3133a6d..a028942 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3759,22 +3759,89 @@
   UNREACHABLE();
 }
 
+static void ThrowSignatureCheckResolveReturnTypeException(Handle<mirror::Class> klass,
+                                                          Handle<mirror::Class> super_klass,
+                                                          Handle<mirror::ArtMethod> method,
+                                                          mirror::ArtMethod* m)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  DCHECK(Thread::Current()->IsExceptionPending());
+  DCHECK(!m->IsProxyMethod());
+  const DexFile* dex_file = m->GetDexFile();
+  const DexFile::MethodId& method_id = dex_file->GetMethodId(m->GetDexMethodIndex());
+  const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
+  uint16_t return_type_idx = proto_id.return_type_idx_;
+  std::string return_type = PrettyType(return_type_idx, *dex_file);
+  std::string class_loader = PrettyTypeOf(m->GetDeclaringClass()->GetClassLoader());
+  ThrowWrappedLinkageError(klass.Get(),
+                           "While checking class %s method %s signature against %s %s: "
+                           "Failed to resolve return type %s with %s",
+                           PrettyDescriptor(klass.Get()).c_str(),
+                           PrettyMethod(method.Get()).c_str(),
+                           super_klass->IsInterface() ? "interface" : "superclass",
+                           PrettyDescriptor(super_klass.Get()).c_str(),
+                           return_type.c_str(), class_loader.c_str());
+}
+
+static void ThrowSignatureCheckResolveArgException(Handle<mirror::Class> klass,
+                                                   Handle<mirror::Class> super_klass,
+                                                   Handle<mirror::ArtMethod> method,
+                                                   mirror::ArtMethod* m,
+                                                   uint32_t index, uint32_t arg_type_idx)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  DCHECK(Thread::Current()->IsExceptionPending());
+  DCHECK(!m->IsProxyMethod());
+  const DexFile* dex_file = m->GetDexFile();
+  std::string arg_type = PrettyType(arg_type_idx, *dex_file);
+  std::string class_loader = PrettyTypeOf(m->GetDeclaringClass()->GetClassLoader());
+  ThrowWrappedLinkageError(klass.Get(),
+                           "While checking class %s method %s signature against %s %s: "
+                           "Failed to resolve arg %u type %s with %s",
+                           PrettyDescriptor(klass.Get()).c_str(),
+                           PrettyMethod(method.Get()).c_str(),
+                           super_klass->IsInterface() ? "interface" : "superclass",
+                           PrettyDescriptor(super_klass.Get()).c_str(),
+                           index, arg_type.c_str(), class_loader.c_str());
+}
+
+static void ThrowSignatureMismatch(Handle<mirror::Class> klass,
+                                   Handle<mirror::Class> super_klass,
+                                   Handle<mirror::ArtMethod> method,
+                                   const std::string& error_msg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ThrowLinkageError(klass.Get(),
+                    "Class %s method %s resolves differently in %s %s: %s",
+                    PrettyDescriptor(klass.Get()).c_str(),
+                    PrettyMethod(method.Get()).c_str(),
+                    super_klass->IsInterface() ? "interface" : "superclass",
+                    PrettyDescriptor(super_klass.Get()).c_str(),
+                    error_msg.c_str());
+}
+
 static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
+                                                      Handle<mirror::Class> klass,
+                                                      Handle<mirror::Class> super_klass,
                                                       Handle<mirror::ArtMethod> method1,
-                                                      Handle<mirror::ArtMethod> method2,
-                                                      std::string* error_msg)
+                                                      Handle<mirror::ArtMethod> method2)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   {
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType()));
+    if (UNLIKELY(return_type.Get() == nullptr)) {
+      ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1.Get());
+      return false;
+    }
     mirror::Class* other_return_type = method2->GetReturnType();
-    // NOTE: return_type.Get() must be sequenced after method2->GetReturnType().
+    if (UNLIKELY(other_return_type == nullptr)) {
+      ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2.Get());
+      return false;
+    }
     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);
+      ThrowSignatureMismatch(klass, super_klass, method1,
+                             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;
     }
   }
@@ -3782,39 +3849,54 @@
   const DexFile::TypeList* types2 = method2->GetParameterTypeList();
   if (types1 == nullptr) {
     if (types2 != nullptr && types2->Size() != 0) {
-      *error_msg = StringPrintf("Type list mismatch with %s",
-                                PrettyMethod(method2.Get(), true).c_str());
+      ThrowSignatureMismatch(klass, super_klass, method1,
+                             StringPrintf("Type list mismatch with %s",
+                                          PrettyMethod(method2.Get(), true).c_str()));
       return false;
     }
     return true;
   } else if (UNLIKELY(types2 == nullptr)) {
     if (types1->Size() != 0) {
-      *error_msg = StringPrintf("Type list mismatch with %s",
-                                PrettyMethod(method2.Get(), true).c_str());
+      ThrowSignatureMismatch(klass, super_klass, method1,
+                             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());
+    ThrowSignatureMismatch(klass, super_klass, method1,
+                           StringPrintf("Type list mismatch with %s",
+                                        PrettyMethod(method2.Get(), true).c_str()));
     return false;
   }
   for (uint32_t i = 0; i < num_types; ++i) {
     StackHandleScope<1> hs(self);
+    uint32_t param_type_idx = types1->GetTypeItem(i).type_idx_;
     Handle<mirror::Class> param_type(hs.NewHandle(
-        method1->GetClassFromTypeIndex(types1->GetTypeItem(i).type_idx_, true)));
+        method1->GetClassFromTypeIndex(param_type_idx, true)));
+    if (UNLIKELY(param_type.Get() == nullptr)) {
+      ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
+                                             method1.Get(), i, param_type_idx);
+      return false;
+    }
+    uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_;
     mirror::Class* other_param_type =
-        method2->GetClassFromTypeIndex(types2->GetTypeItem(i).type_idx_, true);
-    // NOTE: param_type.Get() must be sequenced after method2->GetClassFromTypeIndex(...).
+        method2->GetClassFromTypeIndex(other_param_type_idx, true);
+    if (UNLIKELY(other_param_type == nullptr)) {
+      ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
+                                             method2.Get(), i, other_param_type_idx);
+      return false;
+    }
     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);
+      ThrowSignatureMismatch(klass, super_klass, method1,
+                             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;
     }
   }
@@ -3828,43 +3910,36 @@
   }
   // Begin with the methods local to the superclass.
   Thread* self = Thread::Current();
-  StackHandleScope<2> hs(self);
+  StackHandleScope<3> hs(self);
+  MutableHandle<mirror::Class> super_klass(hs.NewHandle<mirror::Class>(nullptr));
   MutableHandle<mirror::ArtMethod> h_m(hs.NewHandle<mirror::ArtMethod>(nullptr));
   MutableHandle<mirror::ArtMethod> super_h_m(hs.NewHandle<mirror::ArtMethod>(nullptr));
   if (klass->HasSuperClass() &&
       klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
+    super_klass.Assign(klass->GetSuperClass());
     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()) {
-        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());
+        if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass,
+                                                                h_m, super_h_m))) {
+          self->AssertPendingException();
           return false;
         }
       }
     }
   }
   for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
-    if (klass->GetClassLoader() != klass->GetIfTable()->GetInterface(i)->GetClassLoader()) {
-      uint32_t num_methods = klass->GetIfTable()->GetInterface(i)->NumVirtualMethods();
+    super_klass.Assign(klass->GetIfTable()->GetInterface(i));
+    if (klass->GetClassLoader() != super_klass->GetClassLoader()) {
+      uint32_t num_methods = super_klass->NumVirtualMethods();
       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));
+        super_h_m.Assign(super_klass->GetVirtualMethod(j));
         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());
+          if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass,
+                                                                  h_m, super_h_m))) {
+            self->AssertPendingException();
             return false;
           }
         }
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index b401066..fb81ad2 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -269,6 +269,13 @@
   va_end(args);
 }
 
+void ThrowWrappedLinkageError(mirror::Class* referrer, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  ThrowWrappedException("Ljava/lang/LinkageError;", referrer, fmt, &args);
+  va_end(args);
+}
+
 // NegativeArraySizeException
 
 void ThrowNegativeArraySizeException(int size) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 49890e2..bd667fa 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -134,6 +134,10 @@
     __attribute__((__format__(__printf__, 2, 3)))
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
 
+void ThrowWrappedLinkageError(mirror::Class* referrer, const char* fmt, ...)
+    __attribute__((__format__(__printf__, 2, 3)))
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) COLD_ATTR;
+
 // NegativeArraySizeException
 
 void ThrowNegativeArraySizeException(int size)