Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/jdk/java/lang/ProcessBuilder/ArgCheck.java
66644 views
1
/*
2
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/**
25
* @test
26
* @bug 8282008
27
* @requires (os.family == "windows")
28
* @run main/othervm ArgCheck
29
* @summary Check invocation of exe and non-exe programs using ProcessBuilder
30
* and arguments with spaces, backslashes, and simple quoting.
31
*/
32
33
import java.io.BufferedWriter;
34
import java.io.File;
35
import java.io.FileWriter;
36
import java.io.IOException;
37
import java.io.InputStream;
38
import java.nio.charset.Charset;
39
import java.nio.charset.StandardCharsets;
40
import java.nio.file.Files;
41
import java.nio.file.Path;
42
import java.nio.file.Paths;
43
import java.util.Arrays;
44
import java.util.ArrayList;
45
import java.util.List;
46
import java.util.Objects;
47
48
/**
49
* Class to check invocation of java, .cmd, and vbs scripts with arguments and various quote cases.
50
* Can be run standalone to compare results with other Java versions.
51
*/
52
public class ArgCheck {
53
54
private static final Path SRC_DIR = Paths.get(System.getProperty("test.src", "."));
55
private static final Path WORK_DIR = Paths.get(System.getProperty("user.dir", "."));
56
private static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
57
58
private static final String ECHO_CMD_PATH = WORK_DIR.resolve("EchoArguments.cmd").toString();
59
private static final String ECHO_VBS_PATH = WORK_DIR.resolve("EchoArguments.vbs").toString();
60
61
// Test argument containing both a space and a trailing backslash
62
// Depending on the mode the final backslash may act as an escape that may turn an added quote to a literal quote
63
private static final String SPACE_AND_BACKSLASH = "SPACE AND BACKSLASH\\";
64
private static final char DOUBLE_QUOTE = '"';
65
private static final char BACKSLASH = '\\';
66
67
private static final String AMBIGUOUS_PROP_NAME = "jdk.lang.Process.allowAmbiguousCommands";
68
private static final String AMBIGUOUS_PROP_VALUE = System.getProperty(AMBIGUOUS_PROP_NAME);
69
private static final Boolean AMBIGUOUS_PROP_BOOLEAN = AMBIGUOUS_PROP_VALUE == null ? null :
70
Boolean.valueOf(!"false".equals(AMBIGUOUS_PROP_VALUE));
71
72
private static final List<String> ECHO_JAVA_ARGS = Arrays.asList("java", "-classpath", TEST_CLASSES.toString(), "ArgCheck");
73
private static final List<String> ECHO_CMD_ARGS = Arrays.asList(ECHO_CMD_PATH);
74
private static final List<String> ECHO_VBS_ARGS = Arrays.asList("CScript", "/b", ECHO_VBS_PATH);
75
76
/**
77
* If zero arguments are supplied, run the test cases, by launching each as a child process.
78
* If there are arguments, then this is a child Java process that prints each argument to stdout.
79
* The test can be run manually with -Djdk.lang.Process.allowAmbiguousCommands={"true", "false", ""}
80
* to run a matching subset of the tests.
81
*/
82
public static void main(String[] args) throws IOException {
83
if (args.length > 0) {
84
// Echo supplied arguments and exit
85
for (String arg : args)
86
System.out.println(arg);
87
return;
88
}
89
90
System.out.println("Java Version: " + System.getProperty("java.version"));
91
92
createFiles();
93
94
int errors = 0;
95
int success = 0;
96
int skipped = 0;
97
98
for (CMD cmd : CASES) {
99
// If System property jdk.lang.process.allowAmbiguousCommands matches the case, test it
100
// If undefined, test them all
101
if (AMBIGUOUS_PROP_BOOLEAN == null ||
102
AMBIGUOUS_PROP_BOOLEAN.booleanValue() == cmd.allowAmbiguous) {
103
try {
104
testCommand(cmd);
105
success++;
106
} catch (Exception ex) {
107
ex.printStackTrace();
108
errors++;
109
}
110
} else {
111
// skip unmatched cases
112
skipped++;
113
}
114
}
115
if (skipped > 0) {
116
System.out.printf("%d cases skipped, they did not match the tests with jdk.lang.Process.allowAmbiguousCommands: %s%n",
117
skipped, AMBIGUOUS_PROP_BOOLEAN);
118
}
119
System.out.printf("\nSuccess: %d, errors: %d%n", success, errors);
120
if (errors > 0) {
121
throw new RuntimeException("Errors: " + errors);
122
}
123
}
124
125
/**
126
* A CMD holds the parameters and the expected result of invoking a process with the parameters.
127
*/
128
static class CMD {
129
/**
130
* Construct a test case.
131
* @param allowAmbiguous true/false to set property jdk.lang.Process.allowAmbiguousCommands
132
* @param command list of command parameters to invoke the executable or script
133
* @param arguments list of arguments (appended to the command)
134
* @param expected expected lines of output from invoked command
135
*/
136
CMD(boolean allowAmbiguous, List<String> command, List<String> arguments, List<String> expected) {
137
this.allowAmbiguous = allowAmbiguous;
138
this.command = command;
139
this.arguments = arguments;
140
this.expected = expected;
141
}
142
143
final boolean allowAmbiguous;
144
final List<String> command;
145
final List<String> arguments;
146
final List<String> expected;
147
}
148
149
/**
150
* List of cases with the command, arguments, allowAmbiguous setting, and the expected results
151
*/
152
static final List<CMD> CASES = Arrays.asList(
153
154
// allowAmbiguousCommands = false, without application supplied double-quotes.
155
// The space in the argument requires it to be quoted, the final backslash
156
// must not be allowed to turn the quote that is added into a literal
157
// instead of closing the quote.
158
new CMD(false,
159
ECHO_JAVA_ARGS,
160
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_1"),
161
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_1")),
162
new CMD(false,
163
ECHO_CMD_ARGS,
164
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_2"),
165
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_2")),
166
new CMD(false,
167
ECHO_VBS_ARGS,
168
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_3"),
169
Arrays.asList(SPACE_AND_BACKSLASH + BACKSLASH, "ARG_3")),
170
171
// allowAmbiguousCommands = false, WITH application supplied double-quotes around the argument
172
// The argument has surrounding quotes so does not need further quoting.
173
// However, for exe commands, the final backslash must not be allowed to turn the quote
174
// into a literal instead of closing the quote.
175
new CMD(false,
176
ECHO_JAVA_ARGS,
177
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_11"),
178
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_11")),
179
new CMD(false,
180
ECHO_CMD_ARGS,
181
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_12"),
182
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_12")),
183
new CMD(false,
184
ECHO_VBS_ARGS,
185
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_13"),
186
Arrays.asList(SPACE_AND_BACKSLASH + BACKSLASH, "ARG_13")),
187
188
// Legacy mode tests; allowAmbiguousCommands = true; no application supplied quotes
189
// The space in the argument requires it to be quoted, the final backslash
190
// must not be allowed to turn the quote that is added into a literal
191
// instead of closing the quote.
192
new CMD(true,
193
ECHO_JAVA_ARGS,
194
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_21"),
195
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_21")),
196
new CMD(true,
197
ECHO_CMD_ARGS,
198
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_22"),
199
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + BACKSLASH + DOUBLE_QUOTE, "ARG_22")),
200
new CMD(true,
201
ECHO_VBS_ARGS,
202
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_23"),
203
Arrays.asList(SPACE_AND_BACKSLASH + BACKSLASH, "ARG_23")),
204
205
// allowAmbiguousCommands = true, WITH application supplied double-quotes around the argument
206
// The argument has surrounding quotes so does not need further quoting.
207
// The backslash before the final quote is ignored and is interpreted differently for each command.
208
new CMD(true,
209
ECHO_JAVA_ARGS,
210
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_31"),
211
Arrays.asList("SPACE AND BACKSLASH\" ARG_31")),
212
new CMD(true,
213
ECHO_CMD_ARGS,
214
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_32"),
215
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_32")),
216
new CMD(true,
217
ECHO_VBS_ARGS,
218
Arrays.asList(DOUBLE_QUOTE + SPACE_AND_BACKSLASH + DOUBLE_QUOTE, "ARG_33"),
219
Arrays.asList(SPACE_AND_BACKSLASH, "ARG_33"))
220
);
221
222
/**
223
* Common function to Invoke a process with the commands and check the result.
224
*
225
* @param cmd a CMD test case with arguments, allowAmbiguousCommands mode, and expected output
226
*/
227
private static void testCommand(CMD cmd) throws Exception {
228
System.setProperty(AMBIGUOUS_PROP_NAME, Boolean.toString(cmd.allowAmbiguous));
229
List<String> actual = null;
230
List<String> arguments = new ArrayList<>(cmd.command);
231
arguments.addAll(cmd.arguments);
232
try {
233
// Launch the process and wait for termination
234
ProcessBuilder pb = new ProcessBuilder(arguments);
235
Process process = pb.start();
236
try (InputStream is = process.getInputStream()) {
237
String str = readAllBytesAsString(is);
238
str = str.replace("\r", "");
239
actual = Arrays.asList(str.split("\n"));
240
} catch (IOException ioe) {
241
throw new RuntimeException(ioe.getMessage(), ioe);
242
}
243
int exitCode = process.waitFor();
244
if (exitCode != 0) {
245
actual = new ArrayList(actual);
246
actual.add("Exit code: " + exitCode);
247
}
248
} catch (IOException ioe) {
249
actual = Arrays.asList(ioe.getMessage().replace(arguments.get(0), "CMD"));
250
} catch (Exception ex) {
251
actual = Arrays.asList(ex.getMessage()); // Use exception message as output
252
}
253
if (!Objects.equals(actual, cmd.expected)) {
254
System.out.println("Invoking(" + cmd.allowAmbiguous + "): " + arguments);
255
if (actual.size() != cmd.expected.size()) {
256
System.out.println("Args Length: actual: " + actual.size() + " expected: " + cmd.expected.size());
257
}
258
System.out.println("Actual: " + actual);
259
System.out.println("Expected: " + cmd.expected);
260
System.out.println();
261
throw new RuntimeException("Unexpected output");
262
}
263
}
264
265
/**
266
* Private method to readAllBytes as a String.
267
* (InputStream.readAllBytes is not supported by the JDK until 9)
268
* @param is an InputStream
269
* @return a String with the contents
270
* @throws IOException if an error occurs
271
*/
272
private static String readAllBytesAsString(InputStream is) throws IOException {
273
final int BUF_SIZE = 8192;
274
byte[] bytes = new byte[BUF_SIZE];
275
int off = 0;
276
int len;
277
while ((len = is.read(bytes, off, bytes.length - off)) > 0) {
278
off += len;
279
if (off >= bytes.length) {
280
// no space in buffer, reallocate larger
281
bytes = Arrays.copyOf(bytes, bytes.length + BUF_SIZE);
282
}
283
}
284
return new String(bytes, 0, off, Charset.defaultCharset());
285
}
286
287
/**
288
* Initialize .cmd and .vbs scripts.
289
*
290
* @throws Error if an exception occurs
291
*/
292
private static void createFiles() throws IOException {
293
Files.write(Paths.get(ECHO_CMD_PATH), EchoArgumentsCmd.getBytes(StandardCharsets.UTF_8));
294
Files.write(Paths.get(ECHO_VBS_PATH), EchoArgumentsVbs.getBytes(StandardCharsets.UTF_8));
295
}
296
297
/**
298
* Self contained .cmd to echo each argument on a separate line.
299
*/
300
static final String EchoArgumentsCmd = "@echo off\n" +
301
"set p1=\n" +
302
"set p2=\n" +
303
"\n" +
304
"if not [%1]==[] set p1=%1\n" +
305
"if not [%2]==[] set p2=%2\n" +
306
"if not [%3]==[] set p3=%3\n" +
307
"if defined p1 echo %p1%\n" +
308
"if defined p2 echo %p2%\n" +
309
"if defined p3 echo %p3%\n" +
310
"exit /b 0\n";
311
312
313
/**
314
* Self contained .vbs to echo each argument on a separate line.
315
*/
316
static final String EchoArgumentsVbs = "Option Explicit\n" +
317
"Dim arg\n" +
318
"for each arg in WScript.Arguments\n" +
319
" WScript.StdOut.WriteLine(arg)\n" +
320
"Next\n";
321
}
322
323