ART: Change RETURN_OBJECT verification for arrays

Arrays appear to be valid (as according to spec), even if their
components are erroneous. If a component is erroneous, it may not
have loaded superclass or interface information, and so fail a
direct check for assignability.

Add a cutout that checks whether the declared return-type or the
actual return-type are arrays with erroneous components (and if so,
have the same 'depth'). In that case, generate a soft instead of a
hard error.

Also includes a fix to DumpClass.

Bug: 19683465
Change-Id: Ie73de03adeb0af7e939370d7363684fe125d7994
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 9fa6073..29851a9 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -228,8 +228,12 @@
     os << "  interfaces (" << num_direct_interfaces << "):\n";
     for (size_t i = 0; i < num_direct_interfaces; ++i) {
       Class* interface = GetDirectInterface(self, h_this, i);
-      const ClassLoader* cl = interface->GetClassLoader();
-      os << StringPrintf("    %2zd: %s (cl=%p)\n", i, PrettyClass(interface).c_str(), cl);
+      if (interface == nullptr) {
+        os << StringPrintf("    %2zd: nullptr!\n", i);
+      } else {
+        const ClassLoader* cl = interface->GetClassLoader();
+        os << StringPrintf("    %2zd: %s (cl=%p)\n", i, PrettyClass(interface).c_str(), cl);
+      }
     }
   }
   if (!IsLoaded()) {
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 47e9bf5..988fc0e 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1752,8 +1752,21 @@
               Fail(VERIFY_ERROR_NO_CLASS) << " can't resolve returned type '" << return_type
                   << "' or '" << reg_type << "'";
             } else {
-              Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning '" << reg_type
-                  << "', but expected from declaration '" << return_type << "'";
+              bool soft_error = false;
+              // Check whether arrays are involved. They will show a valid class status, even
+              // if their components are erroneous.
+              if (reg_type.IsArrayTypes() && return_type.IsArrayTypes()) {
+                return_type.CanAssignArray(reg_type, reg_types_, class_loader_, &soft_error);
+                if (soft_error) {
+                  Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "array with erroneous component type: "
+                        << reg_type << " vs " << return_type;
+                }
+              }
+
+              if (!soft_error) {
+                Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning '" << reg_type
+                    << "', but expected from declaration '" << return_type << "'";
+              }
             }
           }
         }
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 201169f..97d0cbe 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -822,5 +822,42 @@
   return os;
 }
 
+bool RegType::CanAssignArray(const RegType& src, RegTypeCache& reg_types,
+                             Handle<mirror::ClassLoader> class_loader, bool* soft_error) const {
+  if (!IsArrayTypes() || !src.IsArrayTypes()) {
+    *soft_error = false;
+    return false;
+  }
+
+  const RegType& cmp1 = reg_types.GetComponentType(*this, class_loader.Get());
+  const RegType& cmp2 = reg_types.GetComponentType(src, class_loader.Get());
+
+  if (cmp1.IsAssignableFrom(cmp2)) {
+    return true;
+  }
+  if (cmp1.IsUnresolvedTypes()) {
+    if (cmp2.IsIntegralTypes() || cmp2.IsFloatTypes() || cmp2.IsArrayTypes()) {
+      *soft_error = false;
+      return false;
+    }
+    *soft_error = true;
+    return false;
+  }
+  if (cmp2.IsUnresolvedTypes()) {
+    if (cmp1.IsIntegralTypes() || cmp1.IsFloatTypes() || cmp1.IsArrayTypes()) {
+      *soft_error = false;
+      return false;
+    }
+    *soft_error = true;
+    return false;
+  }
+  if (!cmp1.IsArrayTypes() || !cmp2.IsArrayTypes()) {
+    *soft_error = false;
+    return false;
+  }
+  return cmp1.CanAssignArray(cmp2, reg_types, class_loader, soft_error);
+}
+
+
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 73e131e..d260650 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -25,6 +25,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "gc_root.h"
+#include "handle_scope.h"
 #include "object_callbacks.h"
 #include "primitive.h"
 
@@ -205,6 +206,17 @@
   bool IsAssignableFrom(const RegType& src) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Can this array type potentially be assigned by src.
+  // This function is necessary as array types are valid even if their components types are not,
+  // e.g., when they component type could not be resolved. The function will return true iff the
+  // types are assignable. It will return false otherwise. In case of return=false, soft_error
+  // will be set to true iff the assignment test failure should be treated as a soft-error, i.e.,
+  // when both array types have the same 'depth' and the 'final' component types may be assignable
+  // (both are reference types).
+  bool CanAssignArray(const RegType& src, RegTypeCache& reg_types,
+                      Handle<mirror::ClassLoader> class_loader, bool* soft_error) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't
   // allow assignment to
   // an interface from an Object.