On Tue, 7 Jul 2026 17:14:35 GMT, Daniel D. Daugherty <[email protected]> wrote:
>> An asynchronous exception sent by JVMTI `StopThread` to a virtual thread can >> be processed and thrown at a point where it is unsafe to do so, leaving the >> virtual thread in an invalid state. The unsafe nature of `StopThread` is not >> an issue exclusive to virtual threads, but due to extra code executed during >> mount/unmount transitions, some tests that are safe for platform threads are >> not for virtual threads. In the reported bug, where the async exception is >> sent to a thread executing `Thread.yield` in a loop, the exception ends up >> being thrown on return from `VirtualThread.startTransition`. Since the >> transition bits remain set, the virtual thread hits the reported assert in >> `MountUnmountDisabler::start_transition` at the next unmount attempt. >> >> A similar issue can happen if the exception is thrown right after executing >> `VirtualThread.endFirstTransition` or right before >> `VirtualThread.startFinalTransition` which can be reproduced by calling >> `StopThread` on virtual threads with empty tasks. >> >> The patch fixes these cases and potentially others that can happen if an >> async exception is thrown while executing a method in the `VirtualThread` >> class, i.e. it improves the robustness of the implementation in the presence >> of async exceptions. It is not an attempt to make `StopThread` bulletproof >> as that would be a more ambitious task. >> >> The proposed changes add two extra checks before installing the asynchronous >> exception handshake. The first verifies that the top method is not a >> `VirtualThread` method. The second verifies that the exception will be >> thrown at the current bytecode, i.e. that exception processing will not be >> deferred to a later safepoint poll where the target might already be in one >> of the unsafe methods. >> >> A less restrictive alternative that avoids that second check is to have the >> target defer processing of the handshake as long as it’s unsafe to do so (as >> based on the first check above). If the handshake is still pending when an >> unmount transition begins, we process it and save the exception in the >> virtual thread’s `JvmtiThreadState` to be thrown at the end of the next >> mount. I have a patch implementing this approach, but the code is a bit more >> involved and I wasn’t convinced it was worth it. >> >> I also refactored `StopThread` by introducing `StopThreadClosure` and >> `StopThreadAsyncClosure` handshake classes. This aligns it with the other >> JVMTI methods that use `JvmtiHandshake`, and also keeps the `StopThread` >> specific logic local to the JV... > > src/hotspot/share/prims/jvmtiEnvBase.cpp line 2458: > >> 2456: _result = JVMTI_ERROR_OPAQUE_FRAME; >> 2457: return; >> 2458: } > > The `!JvmtiEnvBase::is_vthread_suspended(target_h(), _target_jt)` on L2450 > above passes `_target_jt` and that function can dereference `_target_jt`. > > Perhaps the `nullptr` check should be first. Agreed ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/31759#discussion_r3541363997
