Move super class verification to class linker

Verify super classes in the class linker and chain exceptions when super
class verification fails. Add support for dumping chained exceptions to
Throwable::Dump. Improve verifier error detail messages.

Fixes problem where super class verification would leave a pending
exception that would be tripped over elsewhere.

Change-Id: I3ca850fc66674c8601132d7ec40bebbf9c108ae3
diff --git a/src/class_linker.cc b/src/class_linker.cc
index cccf0f6..51e5f3c 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1889,9 +1889,41 @@
   CHECK_EQ(klass->GetStatus(), Class::kStatusResolved) << PrettyClass(klass);
   klass->SetStatus(Class::kStatusVerifying);
 
+  // Verify super class
+  Class* super = klass->GetSuperClass();
+  std::string error_msg;
+  if (super != NULL) {
+    // Acquire lock to prevent races on verifying the super class
+    ObjectLock lock(super);
+
+    if (!super->IsVerified() && !super->IsErroneous()) {
+      Runtime::Current()->GetClassLinker()->VerifyClass(super);
+    }
+    if (!super->IsVerified()) {
+      error_msg = "Rejecting class ";
+      error_msg += PrettyDescriptor(klass);
+      error_msg += " that attempts to sub-class erroneous class ";
+      error_msg += PrettyDescriptor(super);
+      LOG(ERROR) << error_msg  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
+      Thread* self = Thread::Current();
+      SirtRef<Throwable> cause(self->GetException());
+      if (cause.get() != NULL) {
+        self->ClearException();
+      }
+      self->ThrowNewException("Ljava/lang/VerifyError;", error_msg.c_str());
+      if (cause.get() != NULL) {
+        self->GetException()->SetCause(cause.get());
+      }
+      CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass);
+      klass->SetStatus(Class::kStatusError);
+      return;
+    }
+  }
+
   // Try to use verification information from oat file, otherwise do runtime verification
   const DexFile& dex_file = FindDexFile(klass->GetDexCache());
-  if (VerifyClassUsingOatFile(dex_file, klass) || verifier::DexVerifier::VerifyClass(klass)) {
+  if (VerifyClassUsingOatFile(dex_file, klass) ||
+      verifier::DexVerifier::VerifyClass(klass, error_msg)) {
     // Make sure all classes referenced by catch blocks are resolved
     ResolveClassExceptionHandlerTypes(dex_file, klass);
     klass->SetStatus(Class::kStatusVerified);
@@ -1899,12 +1931,12 @@
     CheckMethodsHaveGcMaps(klass);
   } else {
     LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass)
-        << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
+        << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
+        << " because: " << error_msg;
     Thread* self = Thread::Current();
     CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
-    self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Verification of %s failed",
-        PrettyDescriptor(klass).c_str());
-    CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyClass(klass);
+    self->ThrowNewException("Ljava/lang/VerifyError;", error_msg.c_str());
+    CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass);
     klass->SetStatus(Class::kStatusError);
   }
 }