8048190: NoClassDefFoundError omits original ExceptionInInitializerError

Reviewed-by: dholmes, iklam
This commit is contained in:
Coleen Phillimore 2021-08-12 13:45:36 +00:00
parent 7e14c3cc11
commit 464e874a5c
9 changed files with 255 additions and 13 deletions

View file

@ -1015,6 +1015,54 @@ void InstanceKlass::initialize_super_interfaces(TRAPS) {
}
}
ResourceHashtable<const InstanceKlass*, OopHandle, 107, ResourceObj::C_HEAP, mtClass>
_initialization_error_table;
void InstanceKlass::add_initialization_error(JavaThread* current, Handle exception) {
// Create the same exception with a message indicating the thread name,
// and the StackTraceElements.
// If the initialization error is OOM, this might not work, but if GC kicks in
// this would be still be helpful.
JavaThread* THREAD = current;
Handle cause = java_lang_Throwable::get_cause_with_stack_trace(exception, THREAD);
if (HAS_PENDING_EXCEPTION || cause.is_null()) {
CLEAR_PENDING_EXCEPTION;
return;
}
MutexLocker ml(THREAD, ClassInitError_lock);
OopHandle elem = OopHandle(Universe::vm_global(), cause());
bool created = false;
_initialization_error_table.put_if_absent(this, elem, &created);
assert(created, "Initialization is single threaded");
ResourceMark rm(THREAD);
log_trace(class, init)("Initialization error added for class %s", external_name());
}
oop InstanceKlass::get_initialization_error(JavaThread* current) {
MutexLocker ml(current, ClassInitError_lock);
OopHandle* h = _initialization_error_table.get(this);
return (h != nullptr) ? h->resolve() : nullptr;
}
// Need to remove entries for unloaded classes.
void InstanceKlass::clean_initialization_error_table() {
struct InitErrorTableCleaner {
bool do_entry(const InstanceKlass* ik, OopHandle h) {
if (!ik->is_loader_alive()) {
h.release(Universe::vm_global());
return true;
} else {
return false;
}
}
};
MutexLocker ml(ClassInitError_lock);
InitErrorTableCleaner cleaner;
_initialization_error_table.unlink(&cleaner);
}
void InstanceKlass::initialize_impl(TRAPS) {
HandleMark hm(THREAD);
@ -1061,16 +1109,15 @@ void InstanceKlass::initialize_impl(TRAPS) {
if (is_in_error_state()) {
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
ResourceMark rm(THREAD);
const char* desc = "Could not initialize class ";
const char* className = external_name();
size_t msglen = strlen(desc) + strlen(className) + 1;
char* message = NEW_RESOURCE_ARRAY(char, msglen);
if (NULL == message) {
// Out of memory: can't create detailed error message
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
Handle cause(THREAD, get_initialization_error(THREAD));
stringStream ss;
ss.print("Could not initialize class %s", external_name());
if (cause.is_null()) {
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string());
} else {
jio_snprintf(message, msglen, "%s%s", desc, className);
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
ss.as_string(), cause);
}
}
@ -1101,6 +1148,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
CLEAR_PENDING_EXCEPTION;
{
EXCEPTION_MARK;
add_initialization_error(THREAD, e);
// Locks object, set state, and notify all waiting threads
set_initialization_state_and_notify(initialization_error, THREAD);
CLEAR_PENDING_EXCEPTION;
@ -1136,9 +1184,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
// Step 9
if (!HAS_PENDING_EXCEPTION) {
set_initialization_state_and_notify(fully_initialized, CHECK);
{
debug_only(vtable().verify(tty, true);)
}
debug_only(vtable().verify(tty, true);)
}
else {
// Step 10 and 11
@ -1149,6 +1195,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
JvmtiExport::clear_detected_exception(jt);
{
EXCEPTION_MARK;
add_initialization_error(THREAD, e);
set_initialization_state_and_notify(initialization_error, THREAD);
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below
// JVMTI has already reported the pending exception