JDK-8361912 : ThreadsListHandle::cv_internal_thread_to_JavaThread does not deal with a virtual thread's carrier thread
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 19
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2025-07-10
  • Updated: 2025-08-03
  • Resolved: 2025-07-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26 b09Fixed
Related Reports
Causes :  
Relates :  
Relates :  
Relates :  
Description
Looking at ThreadsListHandle::cv_internal_thread_to_JavaThread that function is not dealing with virtual threads. If the passed in jthread resolves to a j.l.Thread that is a virtual thread, then even if mounted, its java_lang_Thread::thread field will be null and so the method will return false, and the outgoing JavaThread* will not be set. Consequently the caller looks at the returned thread oop and checks if it is a virtual thread and if so gets its carrier thread directly - but that resulting JavaThread has not been checked to see if it is protected by the TLH!

We need to make ThreadsListHandle::cv_internal_thread_to_JavaThread deal with virtual threads correctly and "return" the carrier thread when dealing with a mounted virtual thread. This may change the behaviour of callsites that are already dealing with virtual threads, but those callsites are unsafe because of this issue and so need to be fixed regardless.
Comments
Note: most of the usages of cv_internal_thread_to_JavaThread (jvm.cpp, whitebox.cpp, JFR) do not involve virtual threads and so are unaffected by this change (or by the pre-existing behaviour).
03-08-2025

Changeset: 46690051 Branch: master Author: David Holmes <dholmes@openjdk.org> Date: 2025-07-28 23:47:51 +0000 URL: https://git.openjdk.org/jdk/commit/4669005123420d8dbe86740dd9bcbee04735bc4f
28-07-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/26287 Date: 2025-07-14 05:34:57 +0000
21-07-2025

[~sspitsyn] points out that the virtual thread transition disabling is only available when a JVMTI agent is active! That is a significant problem. He also points out that if transitioning is disabled then you have no concerns about carrier threads terminating. This all suggests that we will need different ways to handle virtual thread versus platform threads in a couple of APIs. The approach that will be used involves a retry at the Java level if the VM returns a null result because the target was unmounted, or the carrier had terminated, or the carrier had changed. But those are seperate issues to be dealt with - all we need here is to ensure any returned carrier JavaThread is protected by the TLH.
21-07-2025

We either have to ensure it is not unmounted or else the code that is interacting with the JavaThread needs to realize that it could be unmounted and account for that accordingly. The ThreadSnapshotFactory::get_thread_snapshot code disables virtual thread transitions; however the async_get_stack_trace code does not. In the latter case it can cause the thread to report an empty stack-trace, which seems the wrong thing to do. The whole issue of getting a safe reference to the current carrier thread, and whether that can change, is quite complex and doesn't really mesh well with the existing ThreadsListHandle API.
11-07-2025

When we have a vthread, don't we need to make sure that the vthread is not unmounted after ThreadsListHandle::cv_internal_thread_to_JavaThread() determines that the vthread is protected by the TLH? See this comment: https://github.com/openjdk/jdk/pull/26119#pullrequestreview-3007748260
10-07-2025

Issue was realized whilst looking at the proposed fix for JDK- 8361103, and the prior fix for JDK-8359870
10-07-2025