Verifier can handle an unresolved method or class.

Added a new dex verifier entry point that takes in a ClassDef index and
context instead of a Class pointer. This allows basic structural
verification to still be run on classes that FindClass fails to find. If
the basic structural classes fail, then the compilation for the class is
skipped. Before, an unresolvable malformed class would cause the
compiler to segfault.

Change-Id: Ia02c77560bf274281c4e22250983dc96511501eb
diff --git a/src/compiler.cc b/src/compiler.cc
index e54dd89..4c10305 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -25,6 +25,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "dex_cache.h"
+#include "dex_verifier.h"
 #include "jni_internal.h"
 #include "oat_compilation_unit.h"
 #include "oat_file.h"
@@ -63,14 +64,6 @@
   ByteArray* CreateJniDlsymLookupStub();
 }
 
-namespace verifier {
-  class DexVerifier {
-   public:
-    static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref);
-    static bool IsClassRejected(Compiler::ClassReference ref);
-  };
-}
-
 static double Percentage(size_t x, size_t y) {
   return 100.0 * ((double)x) / ((double)(x + y));
 }
@@ -861,6 +854,20 @@
     Thread* self = Thread::Current();
     CHECK(self->IsExceptionPending());
     self->ClearException();
+
+    /*
+     * At compile time, we can still structurally verify the class even if FindClass fails.
+     * This is to ensure the class is structurally sound for compilation. An unsound class
+     * will be rejected by the verifier and later skipped during compilation in the compiler.
+     */
+    std::string error_msg;
+    if (!verifier::DexVerifier::VerifyClass(context->dex_file, context->dex_cache,
+        context->class_loader, class_def_index, error_msg)) {
+      const DexFile::ClassDef& class_def = context->dex_file->GetClassDef(class_def_index);
+      LOG(ERROR) << "Verification failed on class "
+                 << PrettyDescriptor(context->dex_file->GetClassDescriptor(class_def))
+                 << " because: " << error_msg;
+    }
     return;
   }
   CHECK(klass->IsResolved()) << PrettyClass(klass);
@@ -884,6 +891,7 @@
   Context context;
   context.class_linker = Runtime::Current()->GetClassLinker();
   context.class_loader = class_loader;
+  context.dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   context.dex_file = &dex_file;
   ForAll(&context, 0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
 
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index b68c7d5..064aa44 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -968,7 +968,7 @@
 
 bool DexVerifier::VerifyMethod(Method* method) {
   DexVerifier verifier(method);
-  bool success = verifier.Verify();
+  bool success = verifier.VerifyAll();
   CHECK_EQ(success, verifier.failure_ == VERIFY_ERROR_NONE);
 
   // We expect either success and no verification error, or failure and a generic failure to
@@ -992,13 +992,75 @@
 
 void DexVerifier::VerifyMethodAndDump(Method* method) {
   DexVerifier verifier(method);
-  verifier.Verify();
+  verifier.VerifyAll();
 
   LOG(INFO) << "Dump of method " << PrettyMethod(method) << " "
             << verifier.fail_messages_.str() << std::endl
             << verifier.info_messages_.str() << Dumpable<DexVerifier>(verifier);
 }
 
+bool DexVerifier::VerifyClass(const DexFile* dex_file, DexCache* dex_cache,
+    const ClassLoader* class_loader, uint32_t class_def_idx, std::string& error) {
+  const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
+  const byte* class_data = dex_file->GetClassData(class_def);
+  ClassDataItemIterator it(*dex_file, class_data);
+  while (it.HasNextStaticField() || it.HasNextInstanceField()) {
+    it.Next();
+  }
+  while (it.HasNextDirectMethod()) {
+    uint32_t method_idx = it.GetMemberIndex();
+    if (!VerifyMethod(method_idx, dex_file, dex_cache, class_loader, class_def_idx,
+        it.GetMethodCodeItem())) {
+      error = "Verifier rejected class";
+      error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+      error += " due to bad method ";
+      error += PrettyMethod(method_idx, *dex_file);
+      return false;
+    }
+    it.Next();
+  }
+  while (it.HasNextVirtualMethod()) {
+    uint32_t method_idx = it.GetMemberIndex();
+    if (!VerifyMethod(method_idx, dex_file, dex_cache, class_loader, class_def_idx,
+        it.GetMethodCodeItem())) {
+      error = "Verifier rejected class";
+      error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+      error += " due to bad method ";
+      error += PrettyMethod(method_idx, *dex_file);
+      return false;
+    }
+    it.Next();
+  }
+  return true;
+}
+
+bool DexVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file, DexCache* dex_cache,
+    const ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item) {
+  DexVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item);
+
+  // Without a method*, we can only verify the struture.
+  bool success = verifier.VerifyStructure();
+  CHECK_EQ(success, verifier.failure_ == VERIFY_ERROR_NONE);
+
+  // We expect either success and no verification error, or failure and a generic failure to
+  // reject the class.
+  if (success) {
+    if (verifier.failure_ != VERIFY_ERROR_NONE) {
+      LOG(FATAL) << "Unhandled failure in verification of " << PrettyMethod(method_idx, *dex_file)
+                 << std::endl << verifier.fail_messages_;
+    }
+  } else {
+    LOG(INFO) << "Verification error in " << PrettyMethod(method_idx, *dex_file) << " "
+               << verifier.fail_messages_.str();
+    if (gDebugVerify) {
+      std::cout << std::endl << verifier.info_messages_.str();
+      verifier.Dump(std::cout);
+    }
+    DCHECK_EQ(verifier.failure_, VERIFY_ERROR_GENERIC);
+  }
+  return success;
+}
+
 DexVerifier::DexVerifier(Method* method)
     : work_insn_idx_(-1),
       method_(method),
@@ -1006,13 +1068,31 @@
       new_instance_count_(0),
       monitor_enter_count_(0) {
   CHECK(method != NULL);
-  const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
+  dex_cache_ = method->GetDeclaringClass()->GetDexCache();
+  class_loader_ = method->GetDeclaringClass()->GetClassLoader();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  dex_file_ = &class_linker->FindDexFile(dex_cache);
+  dex_file_ = &class_linker->FindDexFile(dex_cache_);
   code_item_ = dex_file_->GetCodeItem(method->GetCodeItemOffset());
+  const DexFile::ClassDef* class_def = ClassHelper(method_->GetDeclaringClass()).GetClassDef();
+  class_def_idx_ = dex_file_->GetIndexForClassDef(*class_def);
 }
 
-bool DexVerifier::Verify() {
+DexVerifier::DexVerifier(const DexFile* dex_file, DexCache* dex_cache,
+    const ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item)
+    : work_insn_idx_(-1),
+      method_(NULL),
+      dex_file_(dex_file),
+      dex_cache_(dex_cache),
+      class_loader_(class_loader),
+      class_def_idx_(class_def_idx),
+      code_item_(code_item),
+      failure_(VERIFY_ERROR_NONE),
+      new_instance_count_(0),
+      monitor_enter_count_(0) {
+}
+
+bool DexVerifier::VerifyAll() {
+  CHECK(method_ != NULL);
   // If there aren't any instructions, make sure that's expected, then exit successfully.
   if (code_item_ == NULL) {
     if (!method_->IsNative() && !method_->IsAbstract()) {
@@ -1022,6 +1102,13 @@
       return true;
     }
   }
+  return VerifyStructure() && VerifyCodeFlow();
+}
+
+bool DexVerifier::VerifyStructure() {
+  if (code_item_ == NULL) {
+    return true;
+  }
   // Sanity-check the register counts. ins + locals = registers, so make sure that ins <= registers.
   if (code_item_->ins_size_ > code_item_->registers_size_) {
     Fail(VERIFY_ERROR_GENERIC) << "bad register counts (ins=" << code_item_->ins_size_
@@ -1036,8 +1123,6 @@
   result = result && ScanTryCatchBlocks();
   // Perform static instruction verification.
   result = result && VerifyInstructions();
-  // Perform code flow analysis.
-  result = result && VerifyCodeFlow();
   return result;
 }
 
@@ -1060,9 +1145,7 @@
       // Generic failures at compile time will still fail at runtime, so the class is marked as
       // rejected to prevent it from being compiled.
       case VERIFY_ERROR_GENERIC: {
-        const DexFile::ClassDef* class_def = ClassHelper(method_->GetDeclaringClass()).GetClassDef();
-        CHECK(class_def != NULL);
-        Compiler::ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def));
+        Compiler::ClassReference ref(dex_file_, class_def_idx_);
         AddRejectedClass(ref);
         break;
       }
@@ -1155,7 +1238,8 @@
       // Ensure exception types are resolved so that they don't need resolution to be delivered,
       // unresolved exception types will be ignored by exception delivery
       if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
-        Class* exception_type = linker->ResolveType(iterator.GetHandlerTypeIndex(), method_);
+        Class* exception_type = linker->ResolveType(*dex_file_, iterator.GetHandlerTypeIndex(),
+                                                    dex_cache_, class_loader_);
         if (exception_type == NULL) {
           DCHECK(Thread::Current()->IsExceptionPending());
           Thread::Current()->ClearException();
@@ -1636,7 +1720,7 @@
 }
 
 void DexVerifier::Dump(std::ostream& os) {
-  if (method_->IsNative()) {
+  if (code_item_ == NULL) {
     os << "Native method" << std::endl;
     return;
   }
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 3008793..f4c0f43 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -34,6 +34,8 @@
 
 namespace art {
 
+struct ReferenceMap2Visitor;
+
 #if defined(ART_USE_LLVM_COMPILER)
 namespace compiler_llvm {
   class InferredRegCategoryMap;
@@ -876,30 +878,13 @@
  public:
   /* Verify a class. Returns "true" on success. */
   static bool VerifyClass(const Class* klass, std::string& error);
+
   /*
-   * Perform verification on a single method.
-   *
-   * We do this in three passes:
-   *  (1) Walk through all code units, determining instruction locations,
-   *      widths, and other characteristics.
-   *  (2) Walk through all code units, performing static checks on
-   *      operands.
-   *  (3) Iterate through the method, checking type safety and looking
-   *      for code flow problems.
-   *
-   * Some checks may be bypassed depending on the verification mode. We can't
-   * turn this stuff off completely if we want to do "exact" GC.
-   *
-   * Confirmed here:
-   * - code array must not be empty
-   * Confirmed by ComputeWidthsAndCountOps():
-   * - opcode of first instruction begins at index 0
-   * - only documented instructions may appear
-   * - each instruction follows the last
-   * - last byte of last instruction is at (code_length-1)
+   * Structurally verify a class. Returns "true" on success. Used at compile time
+   * when the pointer for the method or declaring class can't be resolved.
    */
-  static bool VerifyMethod(Method* method);
-  static void VerifyMethodAndDump(Method* method);
+  static bool VerifyClass(const DexFile* dex_file, DexCache* dex_cache,
+      const ClassLoader* class_loader, uint32_t class_def_idx, std::string& error);
 
   uint8_t EncodePcToReferenceMapData() const;
 
@@ -932,8 +917,55 @@
  private:
 
   explicit DexVerifier(Method* method);
+  explicit DexVerifier(const DexFile* dex_file, DexCache* dex_cache,
+      const ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item);
 
-  bool Verify();
+  /*
+   * Perform verification on a single method.
+   *
+   * We do this in three passes:
+   *  (1) Walk through all code units, determining instruction locations,
+   *      widths, and other characteristics.
+   *  (2) Walk through all code units, performing static checks on
+   *      operands.
+   *  (3) Iterate through the method, checking type safety and looking
+   *      for code flow problems.
+   *
+   * Some checks may be bypassed depending on the verification mode. We can't
+   * turn this stuff off completely if we want to do "exact" GC.
+   *
+   * Confirmed here:
+   * - code array must not be empty
+   * Confirmed by ComputeWidthsAndCountOps():
+   * - opcode of first instruction begins at index 0
+   * - only documented instructions may appear
+   * - each instruction follows the last
+   * - last byte of last instruction is at (code_length-1)
+   */
+  static bool VerifyMethod(Method* method);
+  static void VerifyMethodAndDump(Method* method);
+
+  /*
+   * Perform structural verification on a single method. Used at compile time
+   * when the pointer for the method or declaring class can't be resolved.
+   *
+   * We do this in two passes:
+   *  (1) Walk through all code units, determining instruction locations,
+   *      widths, and other characteristics.
+   *  (2) Walk through all code units, performing static checks on
+   *      operands.
+   *
+   * Code flow verification is skipped since a resolved method and class are
+   * necessary to perform all the checks.
+   */
+  static bool VerifyMethod(uint32_t method_idx, const DexFile* dex_file, DexCache* dex_cache,
+      const ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item);
+
+  /* Run both structural and code flow verification on the method. */
+  bool VerifyAll();
+
+  /* Perform structural verification on a single method. */
+  bool VerifyStructure();
 
   /*
    * Compute the width of the instruction at each address in the instruction stream, and store it in
@@ -1284,6 +1316,9 @@
 
   Method* method_;  // The method we're working on.
   const DexFile* dex_file_;  // The dex file containing the method.
+  DexCache* dex_cache_;  // The dex_cache for the declaring class of the method.
+  const ClassLoader* class_loader_;  // The class loader for the declaring class of the method.
+  uint32_t class_def_idx_;  // The class def index of the declaring class of the method.
   const DexFile::CodeItem* code_item_;  // The code item containing the code for the method.
   UniquePtr<InsnFlags[]> insn_flags_;  // Instruction widths and flags, one entry per code unit.
 
@@ -1298,6 +1333,8 @@
   // The number of occurrences of specific opcodes.
   size_t new_instance_count_;
   size_t monitor_enter_count_;
+
+  friend struct art::ReferenceMap2Visitor; // for VerifyMethodAndDump
 };
 
 // Lightweight wrapper for PC to reference bit maps.