From 639815628cf52a4a944a4322cb09da37cded2de9 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Thu, 17 Apr 2014 12:28:43 -0700 Subject: [PATCH] Fix a class-loading bug in the verifier when throwing NPE 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 | 16 ++++++++++------ runtime/verifier/reg_type_cache.cc | 24 ++++++++++++++---------- runtime/verifier/reg_type_cache.h | 6 +----- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 5a9d27cea..dbde7c763 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -392,7 +392,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m SirtRef dex_cache(self, mh.GetDexCache()); SirtRef 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(); diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 9dd57b880..111e8679c 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -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. diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index 4cc7e6127..70d5f0731 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -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) -- 2.11.0