ART: Fix verifier mishandling erroneous array component types

The verifier must not assume that component types are not erroneous.

Bug: 16661259

(cherry picked from commit aa910d5ef43256102809e397de305c23f1c315e6)

Change-Id: I6d607310593ac337616581bfdff5eb29a8dd1b9d
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 2a77341..c668dff 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -21,6 +21,7 @@
 #include "mirror/array.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
+#include "mirror/object_reference.h"
 #include "verifier/method_verifier.h"
 #include <functional>
 
@@ -813,6 +814,7 @@
   if (!SLOW_FIELD_PATH && field_info.FastGet() &&
       (!field_info.IsVolatile() || SupportsVolatileLoadStore(load_size))) {
     RegisterClass reg_class = RegClassForFieldLoadStore(load_size, field_info.IsVolatile());
+    // A load of the class will lead to an iget with offset 0.
     DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
     rl_obj = LoadValue(rl_obj, kRefReg);
     GenNullCheck(rl_obj.reg, opt_flags);
@@ -870,7 +872,9 @@
   if (!SLOW_FIELD_PATH && field_info.FastPut() &&
       (!field_info.IsVolatile() || SupportsVolatileLoadStore(store_size))) {
     RegisterClass reg_class = RegClassForFieldLoadStore(store_size, field_info.IsVolatile());
-    DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
+    // Dex code never writes to the class field.
+    DCHECK_GE(static_cast<uint32_t>(field_info.FieldOffset().Int32Value()),
+              sizeof(mirror::HeapReference<mirror::Class>));
     rl_obj = LoadValue(rl_obj, kRefReg);
     if (is_long_or_double) {
       rl_src = LoadValueWide(rl_src, reg_class);
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 08cff99..d3fcb55 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -19,6 +19,8 @@
 
 #include "dex_cache.h"
 
+#include "base/logging.h"
+#include "mirror/class.h"
 #include "runtime.h"
 
 namespace art {
@@ -41,6 +43,12 @@
   }
 }
 
+inline void DexCache::SetResolvedType(uint32_t type_idx, Class* resolved) {
+  // TODO default transaction support.
+  DCHECK(resolved == nullptr || !resolved->IsErroneous());
+  GetResolvedTypes()->Set(type_idx, resolved);
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index bfd603a..2c5fbcd 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -103,11 +103,8 @@
     return GetResolvedTypes()->Get(type_idx);
   }
 
-  void SetResolvedType(uint32_t type_idx, Class* resolved) ALWAYS_INLINE
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // TODO default transaction support.
-    GetResolvedTypes()->Set(type_idx, resolved);
-  }
+  void SetResolvedType(uint32_t type_idx, Class* resolved)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ArtMethod* GetResolvedMethod(uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index ff9edbb..e4e20c5 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -186,7 +186,7 @@
     } else {
       entry = new ReferenceType(klass, descriptor, entries_.size());
     }
-    entries_.push_back(entry);
+    AddEntry(entry);
     return *entry;
   } else {  // Class not resolved.
     // We tried loading the class and failed, this might get an exception raised
@@ -199,7 +199,7 @@
     }
     if (IsValidDescriptor(descriptor)) {
       RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
-      entries_.push_back(entry);
+      AddEntry(entry);
       return *entry;
     } else {
       // The descriptor is broken return the unknown type as there's nothing sensible that
@@ -210,7 +210,7 @@
 }
 
 const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
-  DCHECK(klass != nullptr);
+  DCHECK(klass != nullptr && !klass->IsErroneous());
   if (klass->IsPrimitive()) {
     // Note: precise isn't used for primitive classes. A char is assignable to an int. All
     // primitive classes are final.
@@ -230,7 +230,7 @@
     } else {
       entry = new ReferenceType(klass, descriptor, entries_.size());
     }
-    entries_.push_back(entry);
+    AddEntry(entry);
     return *entry;
   }
 }
@@ -340,7 +340,7 @@
   }
   // Create entry.
   RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size());
-  entries_.push_back(entry);
+  AddEntry(entry);
   if (kIsDebugBuild) {
     UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
     std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
@@ -364,7 +364,7 @@
     }
   }
   RegType* entry = new UnresolvedSuperClass(child.GetId(), this, entries_.size());
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -394,7 +394,7 @@
     }
     entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -436,7 +436,7 @@
       return Conflict();
     }
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -499,7 +499,7 @@
     }
     entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -518,7 +518,7 @@
   } else {
     entry = new ImpreciseConstType(value, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -536,7 +536,7 @@
   } else {
     entry = new ImpreciseConstLoType(value, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -554,7 +554,7 @@
   } else {
     entry = new ImpreciseConstHiType(value, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -567,8 +567,15 @@
     return FromDescriptor(loader, component.c_str(), false);
   } else {
     mirror::Class* klass = array.GetClass()->GetComponentType();
-    return FromClass(klass->GetDescriptor().c_str(), klass,
-                     klass->CannotBeAssignedFromOtherTypes());
+    if (klass->IsErroneous()) {
+      // Arrays may have erroneous component types, use unresolved in that case.
+      // We assume that the primitive classes are not erroneous, so we know it is a
+      // reference type.
+      return FromDescriptor(loader, klass->GetDescriptor().c_str(), false);
+    } else {
+      return FromClass(klass->GetDescriptor().c_str(), klass,
+                       klass->CannotBeAssignedFromOtherTypes());
+    }
   }
 }
 
@@ -587,5 +594,9 @@
   }
 }
 
+void RegTypeCache::AddEntry(RegType* new_entry) {
+  entries_.push_back(new_entry);
+}
+
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 70d5f07..f42fdd1 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -154,6 +154,8 @@
   const ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void AddEntry(RegType* new_entry);
+
   template <class Type>
   static Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);