mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-03 10:20:57 +00:00
8379122: Test java/lang/ProcessBuilder/Basic.java fails with 'Exception: java.lang.Error: PATH search algorithm" for multi-call binaries
Reviewed-by: jpai, bpb, stuefe
This commit is contained in:
parent
d88d476e7b
commit
bdf95baebf
@ -64,7 +64,7 @@ import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import static java.lang.System.getenv;
|
||||
import static java.lang.System.out;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
@ -686,21 +686,28 @@ public class Basic {
|
||||
|
||||
// On Alpine Linux, /bin/true and /bin/false are just links to /bin/busybox.
|
||||
// Some tests copy /bin/true and /bin/false to files with a different filename.
|
||||
// However, copying the busbox executable into a file with a different name
|
||||
// However, copying the busybox executable into a file with a different name
|
||||
// won't result in the expected return codes. As workaround, we create
|
||||
// executable files that can be copied and produce the expected return
|
||||
// native executables that can be copied and produce the expected return
|
||||
// values.
|
||||
|
||||
private static class TrueExe {
|
||||
public static String path() { return path; }
|
||||
private static final Path BIN_TRUE_PATH = Paths.get("/bin/true");
|
||||
private static final boolean IS_TRUE_FALSE_SAFE_TO_USE = isTrueFalseSafeToUse();
|
||||
|
||||
private static final String path = path0();
|
||||
private static String path0(){
|
||||
if (!Files.isSymbolicLink(Paths.get("/bin/true"))) {
|
||||
return "/bin/true";
|
||||
private static String path0() {
|
||||
if (IS_TRUE_FALSE_SAFE_TO_USE) {
|
||||
return BIN_TRUE_PATH.toString();
|
||||
} else {
|
||||
File trueExe = new File("true");
|
||||
setFileContents(trueExe, "#!/bin/true\n");
|
||||
trueExe.setExecutable(true);
|
||||
File trueExe = findReplacementCommand("BasicTrue");
|
||||
if (trueExe == null) {
|
||||
// Fall back to a script that invokes /bin/true
|
||||
trueExe = new File("true");
|
||||
setFileContents(trueExe, "#!/bin/true\n");
|
||||
trueExe.setExecutable(true);
|
||||
}
|
||||
return trueExe.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
@ -708,19 +715,39 @@ public class Basic {
|
||||
|
||||
private static class FalseExe {
|
||||
public static String path() { return path; }
|
||||
private static final Path BIN_FALSE_PATH = Paths.get("/bin/false");
|
||||
private static final String path = path0();
|
||||
private static String path0(){
|
||||
if (!Files.isSymbolicLink(Paths.get("/bin/false"))) {
|
||||
return "/bin/false";
|
||||
private static String path0() {
|
||||
|
||||
if (TrueExe.IS_TRUE_FALSE_SAFE_TO_USE) {
|
||||
return BIN_FALSE_PATH.toString();
|
||||
} else {
|
||||
File falseExe = new File("false");
|
||||
setFileContents(falseExe, "#!/bin/false\n");
|
||||
falseExe.setExecutable(true);
|
||||
File falseExe = findReplacementCommand("BasicFalse");
|
||||
if (falseExe == null) {
|
||||
// Fall back to a script that invokes /bin/false
|
||||
falseExe = new File("false");
|
||||
setFileContents(falseExe, "#!/bin/false\n");
|
||||
falseExe.setExecutable(true);
|
||||
}
|
||||
return falseExe.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if /bin/true and /bin/false are ok to use as is.
|
||||
// Neither can be a symbolic link or the same binary as the other.
|
||||
private static boolean isTrueFalseSafeToUse() {
|
||||
try {
|
||||
if (Files.isSymbolicLink(TrueExe.BIN_TRUE_PATH) ||
|
||||
Files.isSymbolicLink(FalseExe.BIN_FALSE_PATH)) {
|
||||
return false;
|
||||
}
|
||||
return Files.isSameFile(TrueExe.BIN_TRUE_PATH, FalseExe.BIN_FALSE_PATH);
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class EnglishUnix {
|
||||
private static final Boolean is =
|
||||
(! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
|
||||
@ -1983,6 +2010,7 @@ public class Basic {
|
||||
// PATH search algorithm on Unix
|
||||
//----------------------------------------------------------------
|
||||
try {
|
||||
System.out.printf("Paths: True: %s, False: %s\n", TrueExe.path(), FalseExe.path());
|
||||
List<String> childArgs = new ArrayList<String>(javaChildArgs);
|
||||
childArgs.add("PATH search algorithm");
|
||||
ProcessBuilder pb = new ProcessBuilder(childArgs);
|
||||
@ -2556,26 +2584,37 @@ public class Basic {
|
||||
private static final String TEST_NATIVEPATH = System.getProperty("test.nativepath");
|
||||
|
||||
// Path where "sleep" program may be found" or null
|
||||
private static final Path SLEEP_PATH = initSleepPath();
|
||||
private static final File SLEEP_PATH = initSleepPath();
|
||||
|
||||
/**
|
||||
* Compute the Path to a sleep executable.
|
||||
* @return a Path to sleep or BasicSleep(.exe) or null if none
|
||||
* @return a path to sleep or BasicSleep(.exe) or null if none
|
||||
*/
|
||||
private static Path initSleepPath() {
|
||||
if (Windows.is() && TEST_NATIVEPATH != null) {
|
||||
// exeBasicSleep is equivalent to sleep on Unix
|
||||
Path exePath = Path.of(TEST_NATIVEPATH).resolve("BasicSleep.exe");
|
||||
private static File initSleepPath() {
|
||||
return Windows.is() ? findReplacementCommand("BasicSleep")
|
||||
: findSystemCommand("sleep");
|
||||
}
|
||||
|
||||
/// Search the NativePath for the command.
|
||||
/// On Windows, include the .exe extension
|
||||
private static File findReplacementCommand(String cmdName) {
|
||||
if (TEST_NATIVEPATH != null) {
|
||||
String fullName = cmdName + (Windows.is() ? ".exe" : "");
|
||||
Path exePath = Path.of(TEST_NATIVEPATH).resolve(fullName);
|
||||
if (Files.isExecutable(exePath)) {
|
||||
return exePath;
|
||||
return exePath.toFile();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Search the usual system paths for the command and return the full Path.
|
||||
private static File findSystemCommand(String cmdName) {
|
||||
List<String> binPaths = List.of("/bin", "/usr/bin");
|
||||
for (String dir : binPaths) {
|
||||
Path exePath = Path.of(dir).resolve("sleep");
|
||||
Path exePath = Path.of(dir).resolve(cmdName);
|
||||
if (Files.isExecutable(exePath)) {
|
||||
return exePath;
|
||||
return exePath.toFile();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
30
test/jdk/java/lang/ProcessBuilder/exeBasicFalse.c
Normal file
30
test/jdk/java/lang/ProcessBuilder/exeBasicFalse.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Command line program to return exit status 1.
|
||||
* Note: the file name prefix "exe" identifies the source should be built into BasicFalse(.exe).
|
||||
*/
|
||||
int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
30
test/jdk/java/lang/ProcessBuilder/exeBasicTrue.c
Normal file
30
test/jdk/java/lang/ProcessBuilder/exeBasicTrue.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Command line program to return exit status 0.
|
||||
* Note: the file name prefix "exe" identifies the source should be built into BasicTrue(.exe).
|
||||
*/
|
||||
int main(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user