Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hotspot/share/prims/jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/prims/jniCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/prims/jniCheck.hpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
}
}
Expand Down
52 changes: 52 additions & 0 deletions src/hotspot/share/runtime/javaThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/runtime/javaThread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,12 @@ class JavaThread: public Thread {
// 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -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();
Expand Down