Verify redefined classes

Test: mma -j40 test-art-host

Change-Id: Ia0b5a0934ed895e37b67c9ae2e819648086280c8
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 058b93a..59cb876 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -56,6 +56,8 @@
 #include "ScopedLocalRef.h"
 #include "ti_class_loader.h"
 #include "transform.h"
+#include "verifier/method_verifier.h"
+#include "verifier/verifier_log_mode.h"
 
 namespace openjdkjvmti {
 
@@ -703,7 +705,6 @@
     }
   }
   LOG(WARNING) << "No verification is done on annotations of redefined classes.";
-  LOG(WARNING) << "Bytecodes of redefinitions are not verified.";
 
   return true;
 }
@@ -766,26 +767,28 @@
   }
 
   // TODO Maybe make an iterable view type to simplify using this.
-  art::mirror::ClassLoader* GetSourceClassLoader(jint klass_index)
+  art::mirror::ClassLoader* GetSourceClassLoader(jint klass_index) const
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return art::down_cast<art::mirror::ClassLoader*>(GetSlot(klass_index, kSlotSourceClassLoader));
   }
-  art::mirror::Object* GetJavaDexFile(jint klass_index) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  art::mirror::Object* GetJavaDexFile(jint klass_index) const
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return GetSlot(klass_index, kSlotJavaDexFile);
   }
-  art::mirror::LongArray* GetNewDexFileCookie(jint klass_index)
+  art::mirror::LongArray* GetNewDexFileCookie(jint klass_index) const
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return art::down_cast<art::mirror::LongArray*>(GetSlot(klass_index, kSlotNewDexFileCookie));
   }
-  art::mirror::DexCache* GetNewDexCache(jint klass_index)
+  art::mirror::DexCache* GetNewDexCache(jint klass_index) const
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return art::down_cast<art::mirror::DexCache*>(GetSlot(klass_index, kSlotNewDexCache));
   }
-  art::mirror::Class* GetMirrorClass(jint klass_index) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  art::mirror::Class* GetMirrorClass(jint klass_index) const
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return art::down_cast<art::mirror::Class*>(GetSlot(klass_index, kSlotMirrorClass));
   }
 
-  art::mirror::ByteArray* GetOriginalDexFileBytes(jint klass_index)
+  art::mirror::ByteArray* GetOriginalDexFileBytes(jint klass_index) const
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return art::down_cast<art::mirror::ByteArray*>(GetSlot(klass_index, kSlotOrigDexFile));
   }
@@ -815,15 +818,15 @@
     SetSlot(klass_index, kSlotOrigDexFile, bytes);
   }
 
-  int32_t Length() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  int32_t Length() const REQUIRES_SHARED(art::Locks::mutator_lock_) {
     return arr_->GetLength() / kNumSlots;
   }
 
  private:
-  art::Handle<art::mirror::ObjectArray<art::mirror::Object>> arr_;
+  mutable art::Handle<art::mirror::ObjectArray<art::mirror::Object>> arr_;
 
   art::mirror::Object* GetSlot(jint klass_index,
-                               DataSlot slot) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+                               DataSlot slot) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
     DCHECK_LT(klass_index, Length());
     return arr_->Get((kNumSlots * klass_index) + slot);
   }
@@ -839,6 +842,31 @@
   DISALLOW_COPY_AND_ASSIGN(RedefinitionDataHolder);
 };
 
+// TODO Stash and update soft failure state
+bool Redefiner::ClassRedefinition::CheckVerification(int32_t klass_index,
+                                                     const RedefinitionDataHolder& holder) {
+  DCHECK_EQ(dex_file_->NumClassDefs(), 1u);
+  art::StackHandleScope<2> hs(driver_->self_);
+  std::string error;
+  // TODO Make verification log level lower
+  art::verifier::MethodVerifier::FailureKind failure =
+      art::verifier::MethodVerifier::VerifyClass(driver_->self_,
+                                                 dex_file_.get(),
+                                                 hs.NewHandle(holder.GetNewDexCache(klass_index)),
+                                                 hs.NewHandle(GetClassLoader()),
+                                                 dex_file_->GetClassDef(0), /*class_def*/
+                                                 nullptr, /*compiler_callbacks*/
+                                                 false, /*allow_soft_failures*/
+                                                 /*log_level*/
+                                                 art::verifier::HardFailLogMode::kLogWarning,
+                                                 &error);
+  bool passes = failure == art::verifier::MethodVerifier::kNoFailure;
+  if (!passes) {
+    RecordFailure(ERR(FAILS_VERIFICATION), "Failed to verify class. Error was: " + error);
+  }
+  return passes;
+}
+
 // Looks through the previously allocated cookies to see if we need to update them with another new
 // dexfile. This is so that even if multiple classes with the same classloader are redefined at
 // once they are all added to the classloader.
@@ -978,6 +1006,17 @@
   }
 }
 
+bool Redefiner::CheckAllClassesAreVerified(const RedefinitionDataHolder& holder) {
+  int32_t cnt = 0;
+  for (Redefiner::ClassRedefinition& redef : redefinitions_) {
+    if (!redef.CheckVerification(cnt, holder)) {
+      return false;
+    }
+    cnt++;
+  }
+  return true;
+}
+
 jvmtiError Redefiner::Run() {
   art::StackHandleScope<1> hs(self_);
   // Allocate an array to hold onto all java temporary objects associated with this redefinition.
@@ -997,7 +1036,8 @@
   // try loop.
   if (!CheckAllRedefinitionAreValid() ||
       !EnsureAllClassAllocationsFinished() ||
-      !FinishAllRemainingAllocations(holder)) {
+      !FinishAllRemainingAllocations(holder) ||
+      !CheckAllClassesAreVerified(holder)) {
     // TODO Null out the ClassExt fields we allocated (if possible, might be racing with another
     // redefineclass call which made it even bigger. Leak shouldn't be huge (2x array of size
     // declared_methods_.length) but would be good to get rid of. All other allocations should be