OSDN Git Service

Fix a class-loading bug in the verifier when throwing NPE
authorAndreas Gampe <agampe@google.com>
Thu, 17 Apr 2014 19:28:43 +0000 (12:28 -0700)
committerAndreas Gampe <agampe@google.com>
Thu, 17 Apr 2014 21:10:24 +0000 (21:10 +0000)
When throwing an NPE for invocation, we try to resolve the class of
the method being called. When in the interpreter and having quickened
code, that failed.

Bug: 14133618
Change-Id: I4964b908bb26a82a12263fb86f5dc39c9042479b

runtime/verifier/method_verifier.cc
runtime/verifier/reg_type_cache.cc
runtime/verifier/reg_type_cache.h

index 5a9d27c..dbde7c7 100644 (file)
@@ -392,7 +392,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m
   SirtRef<mirror::DexCache> dex_cache(self, mh.GetDexCache());
   SirtRef<mirror::ClassLoader> class_loader(self, mh.GetClassLoader());
   MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
-                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false,
+                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
                           true);
   return verifier.FindInvokedMethodAtDexPc(dex_pc);
 }
@@ -3119,18 +3119,22 @@ mirror::ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst
          inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
   const RegType& actual_arg_type = reg_line->GetInvocationThis(inst, is_range);
   if (actual_arg_type.IsConflict()) {  // GetInvocationThis failed.
-    return NULL;
+    return nullptr;
   } else if (actual_arg_type.IsZero()) {  // Invoke on "null" instance: we can't go further.
-    return NULL;
+    return nullptr;
   }
   mirror::Class* this_class = NULL;
   if (!actual_arg_type.IsUnresolvedTypes()) {
     this_class = actual_arg_type.GetClass();
   } else {
     const std::string& descriptor(actual_arg_type.GetDescriptor());
-    // TODO: Precise or not?
-    this_class = reg_types_.FromDescriptor(class_loader_->get(), descriptor.c_str(),
-                                           false).GetClass();
+    // Try to resolve type.
+    const RegType& resolved_arg_type = reg_types_.FromDescriptor(class_loader_->get(),
+                                                                 descriptor.c_str(), false);
+    if (!resolved_arg_type.HasClass()) {
+      return nullptr;  // Resolution failed.
+    }
+    this_class = resolved_arg_type.GetClass();
     if (this_class == NULL) {
       Thread* self = Thread::Current();
       self->ClearException();
index 9dd57b8..111e867 100644 (file)
@@ -156,15 +156,6 @@ mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassL
   return klass;
 }
 
-void RegTypeCache::ClearException() {
-  if (can_load_classes_) {
-    DCHECK(Thread::Current()->IsExceptionPending());
-    Thread::Current()->ClearException();
-  } else {
-    DCHECK(!Thread::Current()->IsExceptionPending());
-  }
-}
-
 const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
                                   bool precise) {
   // Try looking up the class in the cache first.
@@ -199,7 +190,12 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descr
   } else {  // Class not resolved.
     // We tried loading the class and failed, this might get an exception raised
     // so we want to clear it before we go on.
-    ClearException();
+    if (can_load_classes_) {
+      DCHECK(Thread::Current()->IsExceptionPending());
+      Thread::Current()->ClearException();
+    } else {
+      DCHECK(!Thread::Current()->IsExceptionPending());
+    }
     if (IsValidDescriptor(descriptor)) {
       RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
       entries_.push_back(entry);
@@ -238,6 +234,14 @@ const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* kl
   }
 }
 
+RegTypeCache::RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
+  if (kIsDebugBuild && can_load_classes) {
+    Thread::Current()->AssertThreadSuspensionIsAllowable();
+  }
+  entries_.reserve(64);
+  FillPrimitiveAndSmallConstantTypes();
+}
+
 RegTypeCache::~RegTypeCache() {
   CHECK_LE(primitive_count_, entries_.size());
   // Delete only the non primitive types.
index 4cc7e61..70d5f07 100644 (file)
@@ -38,10 +38,7 @@ class RegType;
 
 class RegTypeCache {
  public:
-  explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
-    entries_.reserve(64);
-    FillPrimitiveAndSmallConstantTypes();
-  }
+  explicit RegTypeCache(bool can_load_classes);
   ~RegTypeCache();
   static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (!RegTypeCache::primitive_initialized_) {
@@ -152,7 +149,6 @@ class RegTypeCache {
   void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void ClearException();
   bool MatchDescriptor(size_t idx, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise)