diff options
-rw-r--r-- | runtime/class_linker.cc | 14 | ||||
-rw-r--r-- | runtime/class_linker.h | 2 | ||||
-rw-r--r-- | runtime/runtime.cc | 31 | ||||
-rw-r--r-- | runtime/runtime.h | 4 |
4 files changed, 42 insertions, 9 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 7ba0d9216a..0746e0ca06 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2015,10 +2015,18 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, if (descriptor[0] == '[') { return CreateArrayClass(self, descriptor, class_loader); } else if (class_loader.Get() == nullptr) { + // The boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); if (pair.second != nullptr) { StackHandleScope<1> hs(self); return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second); + } else { + // The boot class loader is searched ahead of the application class loader, failures are + // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to + // trigger the chaining with a proper stack trace. + mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); + self->SetException(ThrowLocation(), pre_allocated); + return nullptr; } } else if (Runtime::Current()->UseCompileTimeClassPath()) { // First try with the bootstrap class loader. @@ -2028,7 +2036,8 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, return EnsureResolved(self, descriptor, klass); } } - // If the lookup failed search the boot class path. We don't perform a recursive call to avoid a NoClassDefFoundError being allocated. + // If the lookup failed search the boot class path. We don't perform a recursive call to avoid + // a NoClassDefFoundError being allocated. ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_); if (pair.second != nullptr) { StackHandleScope<1> hs(self); @@ -2057,6 +2066,7 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, ScopedLocalRef<jobject> class_name_object(soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str())); if (class_name_object.get() == nullptr) { + DCHECK(self->IsExceptionPending()); // OOME. return nullptr; } CHECK(class_loader_object.get() != nullptr); @@ -2070,7 +2080,7 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, } else if (result.get() == nullptr) { // broken loader - throw NPE to be compatible with Dalvik ThrowNullPointerException(nullptr, StringPrintf("ClassLoader.loadClass returned null for %s", - class_name_string.c_str()).c_str()); + class_name_string.c_str()).c_str()); return nullptr; } else { // success, return mirror::Class* diff --git a/runtime/class_linker.h b/runtime/class_linker.h index bb6b1c8781..064a85d130 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -85,7 +85,7 @@ class ClassLinker { mirror::Class* FindArrayClass(Thread* self, mirror::Class** element_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Reutrns true if the class linker is initialized. + // Returns true if the class linker is initialized. bool IsInitialized() const; // Define a new a class based on a ClassDef from a DexFile diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 5f9a3e36c9..1a682fb2e0 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -636,7 +636,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize); std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized)); - if (options.get() == NULL) { + if (options.get() == nullptr) { LOG(ERROR) << "Failed to parse options"; return false; } @@ -759,9 +759,9 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) // ClassLinker needs an attached thread, but we can't fully attach a thread without creating // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main // thread, we do not get a java peer. - Thread* self = Thread::Attach("main", false, NULL, false); + Thread* self = Thread::Attach("main", false, nullptr, false); CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId); - CHECK(self != NULL); + CHECK(self != nullptr); // Set us to runnable so tools using a runtime can allocate and GC by default self->TransitionFromSuspendedToRunnable(); @@ -791,11 +791,11 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) } } } else { - CHECK(options->boot_class_path_ != NULL); + CHECK(options->boot_class_path_ != nullptr); CHECK_NE(options->boot_class_path_->size(), 0U); class_linker_->InitWithoutImage(*options->boot_class_path_); } - CHECK(class_linker_ != NULL); + CHECK(class_linker_ != nullptr); verifier::MethodVerifier::Init(); method_trace_ = options->method_trace_; @@ -821,6 +821,13 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL)); self->ClearException(); + // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class + // ahead of checking the application's class loader. + self->ThrowNewException(ThrowLocation(), "Ljava/lang/NoClassDefFoundError;", + "Class not found using the boot class loader; no stack available"); + pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(NULL)); + self->ClearException(); + // Look for a native bridge. native_bridge_library_filename_ = options->native_bridge_library_filename_; android::SetupNativeBridge(native_bridge_library_filename_.c_str(), &native_bridge_art_callbacks_); @@ -1031,12 +1038,20 @@ void Runtime::DetachCurrentThread() { mirror::Throwable* Runtime::GetPreAllocatedOutOfMemoryError() { mirror::Throwable* oome = pre_allocated_OutOfMemoryError_.Read(); - if (oome == NULL) { + if (oome == nullptr) { LOG(ERROR) << "Failed to return pre-allocated OOME"; } return oome; } +mirror::Throwable* Runtime::GetPreAllocatedNoClassDefFoundError() { + mirror::Throwable* ncdfe = pre_allocated_NoClassDefFoundError_.Read(); + if (ncdfe == nullptr) { + LOG(ERROR) << "Failed to return pre-allocated NoClassDefFoundError"; + } + return ncdfe; +} + void Runtime::VisitConstantRoots(RootCallback* callback, void* arg) { // Visit the classes held as static in mirror classes, these can be visited concurrently and only // need to be visited once per GC since they never change. @@ -1075,6 +1090,10 @@ void Runtime::VisitNonThreadRoots(RootCallback* callback, void* arg) { } resolution_method_.VisitRoot(callback, arg, 0, kRootVMInternal); DCHECK(!resolution_method_.IsNull()); + if (!pre_allocated_NoClassDefFoundError_.IsNull()) { + pre_allocated_NoClassDefFoundError_.VisitRoot(callback, arg, 0, kRootVMInternal); + DCHECK(!pre_allocated_NoClassDefFoundError_.IsNull()); + } if (HasImtConflictMethod()) { imt_conflict_method_.VisitRoot(callback, arg, 0, kRootVMInternal); } diff --git a/runtime/runtime.h b/runtime/runtime.h index e97af17faa..03952c48cf 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -246,6 +246,9 @@ class Runtime { mirror::Throwable* GetPreAllocatedOutOfMemoryError() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + mirror::Throwable* GetPreAllocatedNoClassDefFoundError() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector<std::string>& GetProperties() const { return properties_; } @@ -509,6 +512,7 @@ class Runtime { GcRoot<mirror::ArtMethod> callee_save_methods_[kLastCalleeSaveType]; GcRoot<mirror::Throwable> pre_allocated_OutOfMemoryError_; + GcRoot<mirror::Throwable> pre_allocated_NoClassDefFoundError_; GcRoot<mirror::ArtMethod> resolution_method_; GcRoot<mirror::ArtMethod> imt_conflict_method_; GcRoot<mirror::ObjectArray<mirror::ArtMethod>> default_imt_; |