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
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 5a9d27c..dbde7c7 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -392,7 +392,7 @@
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 @@
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 9dd57b8..111e867 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -156,15 +156,6 @@
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 @@
} 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 @@
}
}
+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 4cc7e61..70d5f07 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -38,10 +38,7 @@
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 @@
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)