From 99d2bbf767ac33e1a021c90ba12d95ef37ea4816 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 28 Jun 2024 09:31:14 +0000 Subject: [PATCH] 8334433: jshell.exe runs an executable test.exe on startup Reviewed-by: jpai --- .../jdk/internal/org/jline/utils/OSUtils.java | 2 +- .../jshell/tool/ConsoleIOContext.java | 7 +- .../jdk/jshell/TerminalNoExecTest.java | 96 +++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/langtools/jdk/jshell/TerminalNoExecTest.java diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java index 344d081c124..7fdfb9a028f 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/OSUtils.java @@ -63,7 +63,7 @@ public class OSUtils { String sttyfopt = null; String infocmp = null; String test = null; - String path = System.getenv("PATH"); + String path = "/usr/bin" + File.pathSeparator + "/bin";//was: System.getenv("PATH"); if (path != null) { String[] paths = path.split(File.pathSeparator); for (String p : paths) { diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index a2b1ca0d2d0..f4ca58d6af4 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -154,7 +154,12 @@ class ConsoleIOContext extends IOContext { setupReader = setupReader.andThen(r -> r.option(Option.DISABLE_HIGHLIGHTER, !enableHighlighter)); input.setInputStream(cmdin); } else { - terminal = TerminalBuilder.builder().inputStreamWrapper(in -> { + //on platforms which are known to be fully supported by + //the FFMTerminalProvider, do not permit the ExecTerminalProvider: + boolean allowExecTerminal = !OSUtils.IS_WINDOWS && + !OSUtils.IS_LINUX && + !OSUtils.IS_OSX; + terminal = TerminalBuilder.builder().exec(allowExecTerminal).inputStreamWrapper(in -> { input.setInputStream(in); return nonBlockingInput; }).nativeSignals(false).build(); diff --git a/test/langtools/jdk/jshell/TerminalNoExecTest.java b/test/langtools/jdk/jshell/TerminalNoExecTest.java new file mode 100644 index 00000000000..3d76157fd26 --- /dev/null +++ b/test/langtools/jdk/jshell/TerminalNoExecTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8334433 + * @summary Verify that when running JShell on platforms that support FFMTerminalProvider, + * no new processes are spawned. + * @requires os.family == "windows" | os.family == "mac" | os.family == "linux" + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavaTask TerminalNoExecTest + * @run main TerminalNoExecTest + */ + +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import jdk.jfr.consumer.RecordingStream; +import jdk.jshell.tool.JavaShellToolBuilder; + +import toolbox.ToolBox; + +public class TerminalNoExecTest { + + public static void main(String... args) throws Exception { + if (args.length > 0) { + AtomicBoolean spawnedNewProcess = new AtomicBoolean(); + try (var rs = new RecordingStream()) { + rs.enable("jdk.ProcessStart").withoutThreshold(); + rs.onEvent(evt -> { + System.err.println("evt: " + evt); + spawnedNewProcess.set(true); + }); + rs.startAsync(); + JavaShellToolBuilder.builder().run("--execution=local", "--no-startup"); + rs.stop(); + } + if (spawnedNewProcess.get()) { + System.err.println("Spawned a new process!"); + System.exit(1); + } + System.exit(0); + } else { + Path testScript = Paths.get("do-exit"); + try (Writer w = Files.newBufferedWriter(testScript)) { + w.append("/exit\n"); + } + + ToolBox tb = new ToolBox(); + Process target = + new ProcessBuilder(tb.getJDKTool("java").toString(), + "-classpath", System.getProperty("java.class.path"), + TerminalNoExecTest.class.getName(), + "run-test") + .redirectError(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectInput(testScript.toFile()) + .start(); + + target.waitFor(); + + int exitCode = target.exitValue(); + + if (exitCode != 0) { + throw new AssertionError("Incorrect exit value, expected 0, got: " + exitCode); + } + } + } + +}