Always check for an exception after a class lookup.
This means we need to stop the lookup, as an exception is pending.
Test: 831-unverified-bcp
Bug: 195766785
Change-Id: I8aa65f6bbaae83eff0be7ca5d82e0c0a548b5b60
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 97e22d0..05edb03 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2583,6 +2583,26 @@
return ClassPathEntry(nullptr, nullptr);
}
+// Helper macro to make sure each class loader lookup call handles the case the
+// class loader is not recognized, or the lookup threw an exception.
+#define RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(call_, result_, thread_) \
+do { \
+ auto local_call = call_; \
+ if (!local_call) { \
+ return false; \
+ } \
+ auto local_result = result_; \
+ if (local_result != nullptr) { \
+ return true; \
+ } \
+ auto local_thread = thread_; \
+ if (local_thread->IsExceptionPending()) { \
+ /* Pending exception means there was an error other than */ \
+ /* ClassNotFound that must be returned to the caller. */ \
+ return false; \
+ } \
+} while (0)
+
bool ClassLinker::FindClassInSharedLibraries(ScopedObjectAccessAlreadyRunnable& soa,
Thread* self,
const char* descriptor,
@@ -2602,12 +2622,10 @@
MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
for (auto loader : shared_libraries.Iterate<mirror::ClassLoader>()) {
temp_loader.Assign(loader);
- if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, temp_loader, result)) {
- return false; // One of the shared libraries is not supported.
- }
- if (*result != nullptr) {
- return true; // Found the class up the chain.
- }
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBaseDexClassLoader(soa, self, descriptor, hash, temp_loader, result),
+ *result,
+ self);
}
return true;
}
@@ -2620,7 +2638,8 @@
/*out*/ ObjPtr<mirror::Class>* result) {
// Termination case: boot class loader.
if (IsBootClassLoader(soa, class_loader.Get())) {
- *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash);
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBootClassLoaderClassPath(self, descriptor, hash, result), *result, self);
return true;
}
@@ -2630,26 +2649,24 @@
// - shared libraries
// - class loader dex files
- // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
+ // Create a handle as RegisterDexFile may allocate dex caches (and cause thread suspension).
StackHandleScope<1> hs(self);
Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent()));
- if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result)) {
- return false; // One of the parents is not supported.
- }
- if (*result != nullptr) {
- return true; // Found the class up the chain.
- }
-
- if (!FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result)) {
- return false; // One of the shared library loader is not supported.
- }
- if (*result != nullptr) {
- return true; // Found the class in a shared library.
- }
-
- // Search the current class loader classpath.
- *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
- return !soa.Self()->IsExceptionPending();
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result),
+ *result,
+ self);
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result),
+ *result,
+ self);
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader, result),
+ *result,
+ self);
+ // We did not find a class, but the class loader chain was recognized, so we
+ // return true.
+ return true;
}
if (IsDelegateLastClassLoader(soa, class_loader)) {
@@ -2658,37 +2675,27 @@
// - shared libraries
// - class loader dex files
// - parent
- *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash);
- if (*result != nullptr) {
- return true; // The class is part of the boot class path.
- }
- if (self->IsExceptionPending()) {
- // Pending exception means there was an error other than ClassNotFound that must be returned
- // to the caller.
- return false;
- }
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBootClassLoaderClassPath(self, descriptor, hash, result), *result, self);
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result),
+ *result,
+ self);
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader, result),
+ *result,
+ self);
- if (!FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result)) {
- return false; // One of the shared library loader is not supported.
- }
- if (*result != nullptr) {
- return true; // Found the class in a shared library.
- }
-
- *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
- if (*result != nullptr) {
- return true; // Found the class in the current class loader
- }
- if (self->IsExceptionPending()) {
- // Pending exception means there was an error other than ClassNotFound that must be returned
- // to the caller.
- return false;
- }
-
- // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
+ // Create a handle as RegisterDexFile may allocate dex caches (and cause thread suspension).
StackHandleScope<1> hs(self);
Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent()));
- return FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result);
+ RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+ FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result),
+ *result,
+ self);
+ // We did not find a class, but the class loader chain was recognized, so we
+ // return true.
+ return true;
}
// Unsupported class loader.
@@ -2696,6 +2703,8 @@
return false;
}
+#undef RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION
+
namespace {
// Matches exceptions caught in DexFile.defineClass.
@@ -2723,36 +2732,38 @@
// Finds the class in the boot class loader.
// If the class is found the method returns the resolved class. Otherwise it returns null.
-ObjPtr<mirror::Class> ClassLinker::FindClassInBootClassLoaderClassPath(Thread* self,
- const char* descriptor,
- size_t hash) {
- ObjPtr<mirror::Class> result = nullptr;
+bool ClassLinker::FindClassInBootClassLoaderClassPath(Thread* self,
+ const char* descriptor,
+ size_t hash,
+ /*out*/ ObjPtr<mirror::Class>* result) {
ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
if (pair.second != nullptr) {
ObjPtr<mirror::Class> klass = LookupClass(self, descriptor, hash, nullptr);
if (klass != nullptr) {
- result = EnsureResolved(self, descriptor, klass);
+ *result = EnsureResolved(self, descriptor, klass);
} else {
- result = DefineClass(self,
- descriptor,
- hash,
- ScopedNullHandle<mirror::ClassLoader>(),
- *pair.first,
- *pair.second);
+ *result = DefineClass(self,
+ descriptor,
+ hash,
+ ScopedNullHandle<mirror::ClassLoader>(),
+ *pair.first,
+ *pair.second);
}
- if (result == nullptr) {
+ if (*result == nullptr) {
CHECK(self->IsExceptionPending()) << descriptor;
FilterDexFileCaughtExceptions(self, this);
}
}
- return result;
+ // The boot classloader is always a known lookup.
+ return true;
}
-ObjPtr<mirror::Class> ClassLinker::FindClassInBaseDexClassLoaderClassPath(
+bool ClassLinker::FindClassInBaseDexClassLoaderClassPath(
ScopedObjectAccessAlreadyRunnable& soa,
const char* descriptor,
size_t hash,
- Handle<mirror::ClassLoader> class_loader) {
+ Handle<mirror::ClassLoader> class_loader,
+ /*out*/ ObjPtr<mirror::Class>* result) {
DCHECK(IsPathOrDexClassLoader(soa, class_loader) ||
IsInMemoryDexClassLoader(soa, class_loader) ||
IsDelegateLastClassLoader(soa, class_loader))
@@ -2772,17 +2783,17 @@
};
VisitClassLoaderDexFiles(soa, class_loader, find_class_def);
- ObjPtr<mirror::Class> klass = nullptr;
if (class_def != nullptr) {
- klass = DefineClass(soa.Self(), descriptor, hash, class_loader, *dex_file, *class_def);
- if (UNLIKELY(klass == nullptr)) {
+ *result = DefineClass(soa.Self(), descriptor, hash, class_loader, *dex_file, *class_def);
+ if (UNLIKELY(*result == nullptr)) {
CHECK(soa.Self()->IsExceptionPending()) << descriptor;
FilterDexFileCaughtExceptions(soa.Self(), this);
} else {
DCHECK(!soa.Self()->IsExceptionPending());
}
}
- return klass;
+ // A BaseDexClassLoader is always a known lookup.
+ return true;
}
ObjPtr<mirror::Class> ClassLinker::FindClass(Thread* self,