Skip to content

Commit 97c07a1

Browse files
i556354GoeLin
i556354
authored andcommitted
8234808: jdb quoted option parsing broken
Reviewed-by: phh Backport-of: d1f9b8a
1 parent 5506ecf commit 97c07a1

File tree

4 files changed

+201
-15
lines changed

4 files changed

+201
-15
lines changed

src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Env.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -57,8 +57,8 @@ class Env {
5757
private static HashMap<String, Value> savedValues = new HashMap<String, Value>();
5858
private static Method atExitMethod;
5959

60-
static void init(String connectSpec, boolean openNow, int flags) {
61-
connection = new VMConnection(connectSpec, flags);
60+
static void init(String connectSpec, boolean openNow, int flags, String extraOptions) {
61+
connection = new VMConnection(connectSpec, flags, extraOptions);
6262
if (!connection.isLaunch() || openNow) {
6363
connection.open();
6464
}

src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1047,8 +1047,8 @@ public static void main(String argv[]) throws MissingResourceException {
10471047
/*
10481048
* Here are examples of jdb command lines and how the options
10491049
* are interpreted as arguments to the program being debugged.
1050-
* arg1 arg2
1051-
* ---- ----
1050+
* arg1 arg2
1051+
* ---- ----
10521052
* jdb hello a b a b
10531053
* jdb hello "a b" a b
10541054
* jdb hello a,b a,b
@@ -1085,14 +1085,10 @@ public static void main(String argv[]) throws MissingResourceException {
10851085
connectSpec);
10861086
return;
10871087
}
1088-
connectSpec += "options=" + javaArgs + ",";
10891088
}
10901089

10911090
try {
1092-
if (! connectSpec.endsWith(",")) {
1093-
connectSpec += ","; // (Bug ID 4285874)
1094-
}
1095-
Env.init(connectSpec, launchImmediately, traceFlags);
1091+
Env.init(connectSpec, launchImmediately, traceFlags, javaArgs);
10961092
new TTY();
10971093
} catch(Exception e) {
10981094
MessageOutput.printException("Internal exception:", e);

src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/VMConnection.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,8 @@ private Connector findConnector(String name) {
7878
return null;
7979
}
8080

81-
private Map <String, com.sun.jdi.connect.Connector.Argument> parseConnectorArgs(Connector connector, String argString) {
81+
private Map <String, com.sun.jdi.connect.Connector.Argument>
82+
parseConnectorArgs(Connector connector, String argString, String extraOptions) {
8283
Map<String, com.sun.jdi.connect.Connector.Argument> arguments = connector.defaultArguments();
8384

8485
/*
@@ -121,10 +122,20 @@ private Map <String, com.sun.jdi.connect.Connector.Argument> parseConnectorArgs(
121122
*/
122123
if (name.equals("options")) {
123124
StringBuilder sb = new StringBuilder();
125+
if (extraOptions != null) {
126+
sb.append(extraOptions).append(" ");
127+
// set extraOptions to null to avoid appending it again
128+
extraOptions = null;
129+
}
124130
for (String s : splitStringAtNonEnclosedWhiteSpace(value)) {
131+
boolean wasEnclosed = false;
125132
while (isEnclosed(s, "\"") || isEnclosed(s, "'")) {
133+
wasEnclosed = true;
126134
s = s.substring(1, s.length() - 1);
127135
}
136+
if (wasEnclosed && hasWhitespace(s)) {
137+
s = "\"" + s + "\"";
138+
}
128139
sb.append(s);
129140
sb.append(" ");
130141
}
@@ -150,9 +161,26 @@ private Map <String, com.sun.jdi.connect.Connector.Argument> parseConnectorArgs(
150161
throw new IllegalArgumentException
151162
(MessageOutput.format("Illegal connector argument", argString));
152163
}
164+
if (extraOptions != null) {
165+
// there was no "options" specified in argString
166+
Connector.Argument argument = arguments.get("options");
167+
if (argument != null) {
168+
argument.setValue(extraOptions);
169+
}
170+
}
153171
return arguments;
154172
}
155173

174+
private static boolean hasWhitespace(String string) {
175+
int length = string.length();
176+
for (int i = 0; i < length; i++) {
177+
if (Character.isWhitespace(string.charAt(i))) {
178+
return true;
179+
}
180+
}
181+
return false;
182+
}
183+
156184
private static boolean isEnclosed(String value, String enclosingChar) {
157185
if (value.indexOf(enclosingChar) == 0) {
158186
int lastIndex = value.lastIndexOf(enclosingChar);
@@ -299,7 +327,7 @@ static private boolean isLastChar(char[] arr, int pos) {
299327
return (pos + 1 == arr.length);
300328
}
301329

302-
VMConnection(String connectSpec, int traceFlags) {
330+
VMConnection(String connectSpec, int traceFlags, String extraOptions) {
303331
String nameString;
304332
String argString;
305333
int index = connectSpec.indexOf(':');
@@ -317,7 +345,7 @@ static private boolean isLastChar(char[] arr, int pos) {
317345
(MessageOutput.format("No connector named:", nameString));
318346
}
319347

320-
connectorArgs = parseConnectorArgs(connector, argString);
348+
connectorArgs = parseConnectorArgs(connector, argString, extraOptions);
321349
this.traceFlags = traceFlags;
322350
}
323351

test/jdk/com/sun/jdi/JdbOptions.java

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright (c) 2020, 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 8234808
27+
*
28+
* @library /test/lib
29+
* @run main/othervm JdbOptions
30+
*/
31+
32+
import jdk.test.lib.Platform;
33+
import lib.jdb.Jdb;
34+
import lib.jdb.JdbCommand;
35+
import jdk.test.lib.process.OutputAnalyzer;
36+
37+
import java.lang.management.ManagementFactory;
38+
import java.util.Arrays;
39+
import java.util.List;
40+
41+
class JbdOptionsTarg {
42+
static final String OK_MSG = "JbdOptionsTarg: OK";
43+
44+
static String argString(String s) {
45+
return "arg >" + s + "<";
46+
}
47+
48+
static String propString(String name, String value) {
49+
return "prop[" + name + "] = >" + value + "<";
50+
}
51+
52+
public static void main(String[] args) {
53+
System.out.println(OK_MSG);
54+
// print all args
55+
List<String> vmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();
56+
for (String s: vmArgs) {
57+
System.out.println(argString(s));
58+
}
59+
// print requested sys.props
60+
for (String p: args) {
61+
System.out.println(propString(p, System.getProperty(p)));
62+
}
63+
}
64+
}
65+
66+
public class JdbOptions {
67+
private static final String targ = JbdOptionsTarg.class.getName();
68+
69+
public static void main(String[] args) throws Exception {
70+
// the simplest case
71+
test("-connect",
72+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options=-client -XX:+PrintVMOptions,main=" + targ)
73+
.expectedArg("-XX:+PrintVMOptions");
74+
75+
// pass property through 'options'
76+
test("-connect",
77+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options='-Dboo=foo',main=" + targ + " boo")
78+
.expectedProp("boo", "foo");
79+
80+
// property with spaces
81+
test("-connect",
82+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options=\"-Dboo=foo 2\",main=" + targ + " boo")
83+
.expectedProp("boo", "foo 2");
84+
85+
// property with spaces (with single quotes)
86+
test("-connect",
87+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options='-Dboo=foo 2',main=" + targ + " boo")
88+
.expectedProp("boo", "foo 2");
89+
90+
// properties with spaces (with single quotes)
91+
test("-connect",
92+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options=-Dboo=foo '-Dboo2=foo 2',main=" + targ + " boo boo2")
93+
.expectedProp("boo", "foo")
94+
.expectedProp("boo2", "foo 2");
95+
96+
// 'options' contains commas - values are quoted (double quotes)
97+
test("-connect",
98+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options=\"-client\" \"-XX:+PrintVMOptions\""
99+
+ " \"-XX:StartFlightRecording=dumponexit=true,maxsize=500M\" \"-XX:FlightRecorderOptions=repository=jfrrep\""
100+
+ ",main=" + targ)
101+
.expectedArg("-XX:StartFlightRecording=dumponexit=true,maxsize=500M")
102+
.expectedArg("-XX:FlightRecorderOptions=repository=jfrrep");
103+
104+
// 'options' contains commas - values are quoted (single quotes)
105+
test("-connect",
106+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options='-client' '-XX:+PrintVMOptions'"
107+
+ " '-XX:StartFlightRecording=dumponexit=true,maxsize=500M' '-XX:FlightRecorderOptions=repository=jfrrep'"
108+
+ ",main=" + targ)
109+
.expectedArg("-XX:StartFlightRecording=dumponexit=true,maxsize=500M")
110+
.expectedArg("-XX:FlightRecorderOptions=repository=jfrrep");
111+
112+
// java options are specified in 2 ways, with and without spaces
113+
// options are quoted by using single and double quotes.
114+
test("-Dprop1=val1",
115+
"-Dprop2=val 2",
116+
"-connect",
117+
"com.sun.jdi.CommandLineLaunch:vmexec=java,options=-Dprop3=val3 '-Dprop4=val 4'"
118+
+ " \"-XX:StartFlightRecording=dumponexit=true,maxsize=500M\""
119+
+ " '-XX:FlightRecorderOptions=repository=jfrrep'"
120+
+ ",main=" + targ + " prop1 prop2 prop3 prop4")
121+
.expectedProp("prop1", "val1")
122+
.expectedProp("prop2", "val 2")
123+
.expectedProp("prop3", "val3")
124+
.expectedProp("prop4", "val 4")
125+
.expectedArg("-XX:StartFlightRecording=dumponexit=true,maxsize=500M")
126+
.expectedArg("-XX:FlightRecorderOptions=repository=jfrrep");
127+
128+
}
129+
130+
private static class TestResult {
131+
OutputAnalyzer out;
132+
TestResult(OutputAnalyzer output) {
133+
out = output;
134+
}
135+
TestResult expectedArg(String s) {
136+
out.shouldContain(JbdOptionsTarg.argString(s));
137+
return this;
138+
}
139+
TestResult expectedProp(String name, String value) {
140+
out.shouldContain(JbdOptionsTarg.propString(name, value));
141+
return this;
142+
}
143+
}
144+
145+
private static TestResult test(String... args) throws Exception {
146+
System.out.println();
147+
System.out.println("...testcase...");
148+
if (Platform.isWindows()) {
149+
// on Windows we need to escape quotes
150+
args = Arrays.stream(args)
151+
.map(s -> s.replace("\"", "\\\""))
152+
.toArray(String[]::new);
153+
}
154+
try (Jdb jdb = new Jdb(args)) {
155+
jdb.waitForSimplePrompt(1024, true); // 1024 lines should be enough
156+
jdb.command(JdbCommand.run().allowExit());
157+
OutputAnalyzer out = new OutputAnalyzer(jdb.getJdbOutput());
158+
out.shouldContain(JbdOptionsTarg.OK_MSG);
159+
return new TestResult(out);
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)