OSDN Git Service

ART: Change RETURN_OBJECT verification for arrays
authorAndreas Gampe <agampe@google.com>
Mon, 23 Mar 2015 17:10:20 +0000 (10:10 -0700)
committerAndreas Gampe <agampe@google.com>
Thu, 26 Mar 2015 22:03:46 +0000 (15:03 -0700)
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

runtime/mirror/class.cc
runtime/verifier/method_verifier.cc
runtime/verifier/reg_type.cc
runtime/verifier/reg_type.h

index 9fa6073..29851a9 100644 (file)
@@ -228,8 +228,12 @@ void Class::DumpClass(std::ostream& os, int flags) {
     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()) {
index 47e9bf5..988fc0e 100644 (file)
@@ -1752,8 +1752,21 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
               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 << "'";
+              }
             }
           }
         }
index 201169f..97d0cbe 100644 (file)
@@ -822,5 +822,42 @@ std::ostream& operator<<(std::ostream& os, const RegType& rhs) {
   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
index 73e131e..d260650 100644 (file)
@@ -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 @@ class RegType {
   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.