Avoid JNI call with pending OOME.
If EnsureResolved fails with an exception then FindClassInPathClassLoader may
fall-through to a call to NewStringUTF with a pending exception.
Bug: 15446488
Change-Id: I007f7bee7c50aa588d0b1c776da67a38314dc897
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 68e20f2..e1b79c9 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2060,6 +2060,7 @@
Thread* self, const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader) {
+ // Can we special case for a well understood PathClassLoader with the BootClassLoader as parent?
if (class_loader->GetClass() !=
soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) ||
class_loader->GetParent()->GetClass() !=
@@ -2071,17 +2072,21 @@
if (pair.second != nullptr) {
mirror::Class* klass = LookupClass(self, descriptor, hash, nullptr);
if (klass != nullptr) {
- return EnsureResolved(self, descriptor, klass);
+ // May return null if resolution on another thread fails.
+ klass = EnsureResolved(self, descriptor, klass);
+ } else {
+ // May OOME.
+ klass = DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
+ *pair.second);
}
- klass = DefineClass(self, descriptor, hash, NullHandle<mirror::ClassLoader>(), *pair.first,
- *pair.second);
- if (klass != nullptr) {
- return klass;
+ if (klass == nullptr) {
+ CHECK(self->IsExceptionPending()) << descriptor;
+ self->ClearException();
}
- CHECK(self->IsExceptionPending()) << descriptor;
- self->ClearException();
+ return klass;
} else {
- // RegisterDexFile may allocate dex caches (and cause thread suspension).
+ // Handle as if this is the child PathClassLoader.
+ // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
StackHandleScope<3> hs(self);
// The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
// We need to get the DexPathList and loop through it.
@@ -2138,8 +2143,9 @@
}
}
}
+ self->AssertNoPendingException();
+ return nullptr;
}
- return nullptr;
}
mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 006354f..b78d0b5 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -117,8 +117,8 @@
Handle<mirror::ClassLoader> class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Find a class in the path class loader, loading it if necessary. Hash function is supposed to
- // be ComputeModifiedUtf8Hash(descriptor).
+ // Find a class in the path class loader, loading it if necessary without using JNI. Hash
+ // function is supposed to be ComputeModifiedUtf8Hash(descriptor).
mirror::Class* FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Thread* self, const char* descriptor, size_t hash,
Handle<mirror::ClassLoader> class_loader)