From 92268e17beec15f3fefa6784a48d6f0e1bb9c67a Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Wed, 2 Jul 2025 16:59:29 +0000 Subject: [PATCH] 8359870: JVM crashes in AccessInternal::PostRuntimeDispatch Reviewed-by: alanb, sspitsyn Backport-of: 13a3927855da61fe27f3b43e5e4755d0c5ac5a16 --- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/services/threadService.cpp | 14 +++++++++++--- .../classes/jdk/internal/vm/ThreadDumper.java | 18 ++++++++++++++---- .../jdk/internal/vm/ThreadSnapshot.java | 4 +++- .../DumpThreadsWithEliminatedLock.java | 2 +- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index d669d7bf5ec..c6f1172ca08 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -2966,7 +2966,7 @@ JVM_ENTRY(jobject, JVM_CreateThreadSnapshot(JNIEnv* env, jobject jthread)) oop snapshot = ThreadSnapshotFactory::get_thread_snapshot(jthread, THREAD); return JNIHandles::make_local(THREAD, snapshot); #else - return nullptr; + THROW_NULL(vmSymbols::java_lang_UnsupportedOperationException()); #endif JVM_END diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 8e0c955bff8..57c5f330bfc 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1439,7 +1439,17 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); - Handle thread_h(THREAD, JNIHandles::resolve(jthread)); + + JavaThread* java_thread = nullptr; + oop thread_oop; + bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop); + assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop"); + Handle thread_h(THREAD, thread_oop); + bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); // Deals with null + + if (!has_javathread && !is_virtual) { + return nullptr; // thread terminated so not of interest + } // wrapper to auto delete JvmtiVTMSTransitionDisabler class TransitionDisabler { @@ -1460,8 +1470,6 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { } } transition_disabler; - JavaThread* java_thread = nullptr; - bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); Handle carrier_thread; if (is_virtual) { // 1st need to disable mount/unmount transitions diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java index 58729774f24..a26003a3afb 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java @@ -177,8 +177,11 @@ public class ThreadDumper { container.children().forEach(c -> dumpThreads(c, writer)); } - private static void dumpThread(Thread thread, TextWriter writer) { + private static boolean dumpThread(Thread thread, TextWriter writer) { ThreadSnapshot snapshot = ThreadSnapshot.of(thread); + if (snapshot == null) { + return false; // thread terminated + } Instant now = Instant.now(); Thread.State state = snapshot.threadState(); writer.println("#" + thread.threadId() + " \"" + snapshot.threadName() @@ -217,6 +220,7 @@ public class ThreadDumper { depth++; } writer.println(); + return true; } /** @@ -284,8 +288,9 @@ public class ThreadDumper { Iterator threads = container.threads().iterator(); while (threads.hasNext()) { Thread thread = threads.next(); - dumpThread(thread, jsonWriter); - threadCount++; + if (dumpThread(thread, jsonWriter)) { + threadCount++; + } } jsonWriter.endArray(); // threads @@ -303,11 +308,15 @@ public class ThreadDumper { /** * Write a thread to the given JSON writer. + * @return true if the thread dump was written, false otherwise * @throws UncheckedIOException if an I/O error occurs */ - private static void dumpThread(Thread thread, JsonWriter jsonWriter) { + private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) { Instant now = Instant.now(); ThreadSnapshot snapshot = ThreadSnapshot.of(thread); + if (snapshot == null) { + return false; // thread terminated + } Thread.State state = snapshot.threadState(); StackTraceElement[] stackTrace = snapshot.stackTrace(); @@ -369,6 +378,7 @@ public class ThreadDumper { } jsonWriter.endObject(); + return true; } /** diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java index e0dd4bbc508..4fcbaf24d2e 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java @@ -52,12 +52,14 @@ class ThreadSnapshot { /** * Take a snapshot of a Thread to get all information about the thread. + * Return null if a ThreadSnapshot is not created, for example if the + * thread has terminated. * @throws UnsupportedOperationException if not supported by VM */ static ThreadSnapshot of(Thread thread) { ThreadSnapshot snapshot = create(thread); if (snapshot == null) { - throw new UnsupportedOperationException(); + return null; // thread terminated } if (snapshot.stackTrace == null) { snapshot.stackTrace = EMPTY_STACK; diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java index a2dce62792b..61447d05bfc 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java @@ -168,4 +168,4 @@ public class DumpThreadsWithEliminatedLock { Files.delete(file); return file; } -} \ No newline at end of file +}