JDK-8289613 : Drop use of Thread.stop in jshell
  • Type: Sub-task
  • Component: tools
  • Sub-Component: jshell
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2022-07-02
  • Updated: 2022-09-12
  • Resolved: 2022-09-08
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 20
20 masterFixed
Related Reports
Relates :  
Description
jshell needs to drop its usage of Thread.stop so that this method can be degraded to throw UOE unconditionally.  The usage in jshell seems to be there to deal with looping threads and dealing with the user pressing "control-C". Alternatives to Thread.stop should be explored, maybe it is possible to start a new debuggee VM, maybe the compiler could generate code that checks a flag or interrupt status at back branches, maybe it could use an agent that injects a check. A short term fix may be be to use JDI ThreadReference::stop as this method will continue to work for debuggers.
Comments
Changeset: ffc249ae Author: Adam Sotona <asotona@openjdk.org> Date: 2022-09-08 10:01:24 +0000 URL: https://git.openjdk.org/jdk/commit/ffc249ae2120752a9c0e9de18167b0c16f2de410
08-09-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/10166 Date: 2022-09-05 12:39:41 +0000
05-09-2022

I've proposed a pull request with alternate patch utilizing java.base jdk.internal.org.objectweb.asm package for bytecode instrumentation: https://github.com/openjdk/jdk/pull/10166
05-09-2022

Bytecode instrumentation seems to be the only feasible solution to avoid use of Thread::stop in LocalExecutionControl. Proposed patch using Classfile API to instrument the bytecode is available in openjdk/jdk-sandbox classfile-api-8289610-branch for comments: https://github.com/openjdk/jdk-sandbox/commit/6499fbf6adc8c595b76f8cb3eb0b948968714d3e#diff-c36ffff66439858a380f5d665260d18eef6d57d52157621b2bb731ac2ee1581a
31-08-2022

To break loops and stop thread execution from the inside it is necessary to detect the loops and inject interruption code into the loops. I see user source code modification before compilation as a bit tricky, patching javac as an overkill, so bytecode instrumentation seems to be the only solution for this case. We can (optionally) detect and instrument loops within a bytecode passed through jdk.jshell.execution.DefaultLoaderDelegate.RemoteClassLoader::declare The implementation may inject into every loop a method call of stop-test callback passed to "DOIT_METHOD" as an argument. Or use global static (or thread local) stop-test and instrument all loops in all methods of all classes passed to DefaultLoaderDelegate.RemoteClassLoader::declare. Loops may be identified by branch instruction with negative target offset. The above proposed solution can be relatively easily implemented using new proposed Classfile API JDK-8280389
15-08-2022

FWIW, as far as I can tell, the use is in (jdk.jshell.execution.)LocalExecutionControl. I believe this control is used primarily when the compiled snippets should be run in an existing VM (like the one where the main JShell is running). So, JShell does not have a control over this VM, so it cannot start a new one, or use JDI (and, probably, not even agents, as that would require dynamic attach). The only solution I see is to generate cancel checks in the code JShell generates. The drawback is that this won't be able to stop code that is not generated by JShell. As an imperfect example: javax.swing.SwingUtilities.invokeAndWait(() -> { try { System.in.read(); } catch (Exception ex) { ex.printStackTrace();} }); (Of course, cancelling/stopping just the invokeAndWait will not stop the code running in the AWT Event Dispatch Thread, but at least it allows the user to regain control over the console.) Luckily, I believe the LocalExecutionControl is not used by default.
18-07-2022