8292674: ReportJNIFatalError should print all java frames

Reviewed-by: pchilanomate
This commit is contained in:
David Holmes 2022-12-13 00:04:38 +00:00
parent be69930d9d
commit 829cbc2cb1
6 changed files with 93 additions and 17 deletions

@ -626,7 +626,7 @@ JNI_ENTRY(void, jni_FatalError(JNIEnv *env, const char *msg))
HOTSPOT_JNI_FATALERROR_ENTRY(env, (char *) msg);
tty->print_cr("FATAL ERROR in native method: %s", msg);
thread->print_stack();
thread->print_jni_stack();
os::abort(); // Dump core and abort
JNI_END

@ -142,7 +142,7 @@ static const char * fatal_non_utf8_class_name2 = "\"";
// When in VM state:
static void ReportJNIWarning(JavaThread* thr, const char *msg) {
tty->print_cr("WARNING in native method: %s", msg);
thr->print_stack();
thr->print_jni_stack();
}
// When in NATIVE state:
@ -193,7 +193,7 @@ check_pending_exception(JavaThread* thr) {
IN_VM(
tty->print_cr("WARNING in native method: JNI call made without checking exceptions when required to from %s",
thr->get_pending_jni_exception_check());
thr->print_stack();
thr->print_jni_stack();
)
thr->clear_pending_jni_exception_check(); // Just complain once
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ extern "C" {
// When in VM state:
static inline void ReportJNIFatalError(JavaThread* thr, const char *msg) {
tty->print_cr("FATAL ERROR in native method: %s", msg);
thr->print_stack();
thr->print_jni_stack();
os::abort(true);
}
}

@ -1673,6 +1673,16 @@ oop JavaThread::current_park_blocker() {
return NULL;
}
// Print stack trace for checked JNI warnings and JNI fatal errors.
// This is the external format from above, but selecting the platform
// or vthread as applicable.
void JavaThread::print_jni_stack() {
if (is_vthread_mounted()) {
print_vthread_stack_on(tty);
} else {
print_stack_on(tty);
}
}
void JavaThread::print_stack_on(outputStream* st) {
if (!has_last_Java_frame()) return;
@ -1706,6 +1716,48 @@ void JavaThread::print_stack_on(outputStream* st) {
}
}
void JavaThread::print_vthread_stack_on(outputStream* st) {
assert(is_vthread_mounted(), "Caller should have checked this");
assert(has_last_Java_frame(), "must be");
Thread* current_thread = Thread::current();
ResourceMark rm(current_thread);
HandleMark hm(current_thread);
RegisterMap reg_map(this,
RegisterMap::UpdateMap::include,
RegisterMap::ProcessFrames::include,
RegisterMap::WalkContinuation::include);
ContinuationEntry* cont_entry = last_continuation();
vframe* start_vf = last_java_vframe(&reg_map);
int count = 0;
for (vframe* f = start_vf; f != NULL; f = f->sender()) {
// Watch for end of vthread stack
if (Continuation::is_continuation_enterSpecial(f->fr())) {
assert(cont_entry == Continuation::get_continuation_entry_for_entry_frame(this, f->fr()), "");
if (cont_entry->is_virtual_thread()) {
break;
}
cont_entry = cont_entry->parent();
}
if (f->is_java_frame()) {
javaVFrame* jvf = javaVFrame::cast(f);
java_lang_Throwable::print_stack_element(st, jvf->method(), jvf->bci());
// Print out lock information
if (JavaMonitorsInStackTrace) {
jvf->print_lock_info_on(st, count);
}
} else {
// Ignore non-Java frames
}
// Bail-out case for too deep stacks if MaxJavaStackTraceDepth > 0
count++;
if (MaxJavaStackTraceDepth > 0 && MaxJavaStackTraceDepth == count) return;
}
}
#if INCLUDE_JVMTI
// Rebind JVMTI thread state from carrier to virtual or from virtual to carrier.
JvmtiThreadState* JavaThread::rebind_to_jvmti_thread_state_of(oop thread_oop) {

@ -940,6 +940,12 @@ private:
// Print stack trace in external format
void print_stack_on(outputStream* st);
void print_stack() { print_stack_on(tty); }
void print_vthread_stack_on(outputStream* st);
// Print stack trace for checked JNI warnings and JNI fatal errors.
// This is the external format from above, but selecting the platform
// or vthread as applicable.
void print_jni_stack();
// Print stack traces in various internal formats
void trace_stack() PRODUCT_RETURN;

@ -1,5 +1,6 @@
/*
* Copyright (c) 2021, Red Hat, Inc. All rights reserved.
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,9 +25,11 @@
/**
* @test TestPrimitiveArrayCriticalWithBadParam
* @bug 8269697
* @bug 8269697 8292674
* @summary -Xcheck:jni should catch wrong parameter passed to GetPrimitiveArrayCritical
* @comment Tests reporting with regular thread and virtual thread.
* @library /test/lib
* @enablePreview
* @run main/native TestPrimitiveArrayCriticalWithBadParam
*/
import java.util.List;
@ -47,39 +50,54 @@ public class TestPrimitiveArrayCriticalWithBadParam {
public static void main(String[] args) {
if (args.length > 0) {
test();
test(args[0]);
} else {
runTest();
runTest(false);
runTest(true);
}
}
private static void runTest() {
private static void runTest(boolean useVThread) {
List<String> pbArgs = new ArrayList<>();
pbArgs.add("-XX:-CreateCoredumpOnCrash");
pbArgs.add("-Xcheck:jni");
pbArgs.add("--enable-preview");
pbArgs.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH);
pbArgs.add(TestPrimitiveArrayCriticalWithBadParam.class.getName());
pbArgs.add("test");
pbArgs.add(useVThread ? "vtest" : "test");
try {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(pbArgs.toArray(new String[0]));
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
// -Xcheck:jni should warn the bad parameter
analyzer.shouldContain("FATAL ERROR in native method: Primitive type array expected but not received for JNI array operation");
analyzer.shouldContain("TestPrimitiveArrayCriticalWithBadParam.pin");
analyzer.shouldNotHaveExitValue(0);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void test() {
Object[] objs = new Object[10];
for (int i = 0; i < objs.length; i++) {
objs[i] = new MyClass();
private static void test(String mode) {
Runnable r = () -> {
Object[] objs = new Object[10];
for (int i = 0; i < objs.length; i++) {
objs[i] = new MyClass();
}
pin(objs);
System.out.println("Object array pinned");
unpin(objs);
};
if (mode.equals("vtest")) {
Thread t = Thread.ofVirtual().start(r);
try {
t.join();
} catch (InterruptedException ex) {
throw new Error("unexpected", ex);
}
} else {
r.run();
}
pin(objs);
System.out.println("Object array pinned");
unpin(objs);
}
public static class MyClass {
public Object ref = new Object();