Skip to content

Commit 9bd11ec

Browse files
committed
Fix the JvmOptions parsing of procfs cmdline
1 parent 9bf0122 commit 9bd11ec

File tree

2 files changed

+83
-9
lines changed

2 files changed

+83
-9
lines changed

components/environment/src/main/java/datadog/environment/JvmOptions.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,29 @@ List<String> findVmOptions(String[] procfsCmdline) {
5555
List<String> vmOptions = new ArrayList<>();
5656
// Start at 1 to skip "java" command itself
5757
int index = 1;
58-
// Look for main class or "-jar", end of VM options
58+
// Look for first self-standing argument that is not prefixed with "-" or end of VM options
59+
// Skip "-jar" and the jar file
5960
// Simultaneously, collect all arguments in the VM options
6061
for (; index < procfsCmdline.length; index++) {
6162
String argument = procfsCmdline[index];
6263
if (argument.startsWith("@")) {
6364
vmOptions.addAll(getArgumentsFromFile(argument));
6465
} else {
65-
vmOptions.add(argument);
66-
}
67-
if (!argument.startsWith("-") || "-jar".equals(argument)) {
68-
if (index + 1 < procfsCmdline.length) {
69-
vmOptions.add(procfsCmdline[index + 1]); // jar file or the main class
66+
if ("-jar".equals(argument)) {
67+
// skip "-jar" and the jar file
68+
index++;
69+
continue;
70+
} else if ("-cp".equals(argument)) {
71+
// slurp '-cp' and the classpath
72+
vmOptions.add(argument);
73+
if (index + 1 < procfsCmdline.length) {
74+
argument = procfsCmdline[++index];
75+
}
76+
} else if (!argument.startsWith("-")) {
77+
// end of VM options
78+
break;
7079
}
71-
break;
80+
vmOptions.add(argument);
7281
}
7382
}
7483
// Insert JDK_JAVA_OPTIONS at the start if present and supported

components/environment/src/test/java/datadog/environment/JvmOptionsTest.java

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,23 @@
88
import static java.util.Collections.emptyList;
99
import static java.util.Collections.emptyMap;
1010
import static java.util.Collections.singletonList;
11+
import static java.util.Objects.requireNonNull;
1112
import static org.junit.jupiter.api.Assertions.assertEquals;
1213
import static org.junit.jupiter.api.Assumptions.assumeTrue;
1314
import static org.junit.jupiter.params.provider.Arguments.arguments;
1415

1516
import datadog.environment.CommandLineHelper.Result;
17+
import java.io.BufferedReader;
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.io.InputStreamReader;
21+
import java.util.ArrayList;
22+
import java.util.Collection;
1623
import java.util.HashMap;
1724
import java.util.List;
1825
import java.util.Map;
1926
import java.util.stream.Stream;
27+
import org.junit.jupiter.api.Assertions;
2028
import org.junit.jupiter.params.ParameterizedTest;
2129
import org.junit.jupiter.params.provider.Arguments;
2230
import org.junit.jupiter.params.provider.MethodSource;
@@ -122,12 +130,37 @@ private static Stream<Arguments> procFsCmdLine() {
122130
arguments(
123131
"Java with JAR and options",
124132
new String[]{"java", "-Xmx512m", "-Xms256m", "-jar", "app.jar"},
125-
asList("-Xmx512m", "-Xms256m", "-jar", "app.jar")
133+
asList("-Xmx512m", "-Xms256m")
126134
),
127135
arguments(
128136
"Java from class and options",
129137
new String[]{"java", "-Xmx512m", "-Xms256m", "-cp", "app.jar", "Main"},
130-
asList("-Xmx512m", "-Xms256m", "-cp", "app.jar", "Main")
138+
asList("-Xmx512m", "-Xms256m", "-cp", "app.jar")
139+
),
140+
arguments(
141+
"Java from class and options, mixed",
142+
new String[]{"java", "-Xms256m", "-cp", "app.jar", "-Xmx512m", "Main"},
143+
asList("-Xms256m", "-cp", "app.jar", "-Xmx512m")
144+
),
145+
arguments(
146+
"Args from file",
147+
new String[]{"java", "-Dargfile.prop=test", "-verbose:class", argFile("carriage-return-separated"), "-jar", "app.jar"},
148+
flatten("-Dargfile.prop=test", "-verbose:class", expectedArsFromArgFile("carriage-return-separated"))
149+
),
150+
arguments(
151+
"Args from file",
152+
new String[]{"java", "-Dargfile.prop=test", "-verbose:class", argFile("new-line-separated"), "-jar", "app.jar"},
153+
flatten("-Dargfile.prop=test", "-verbose:class", expectedArsFromArgFile("new-line-separated"))
154+
),
155+
arguments(
156+
"Args from file",
157+
new String[]{"java", "-Dargfile.prop=test", "-verbose:class", argFile("space-separated"), "-jar", "app.jar"},
158+
flatten("-Dargfile.prop=test", "-verbose:class", expectedArsFromArgFile("space-separated"))
159+
),
160+
arguments(
161+
"Args from file",
162+
new String[]{"java", "-Dargfile.prop=test", "-verbose:class", argFile("tab-separated"), "-jar", "app.jar"},
163+
flatten("-Dargfile.prop=test", "-verbose:class", expectedArsFromArgFile("tab-separated"))
131164
));
132165
// spotless:on
133166
}
@@ -157,4 +190,36 @@ private static Map<String, String> env(String... keysAndValues) {
157190
}
158191
return env;
159192
}
193+
194+
private static String argFile(String name) {
195+
return "@src/test/resources/argfiles/" + name + ".txt";
196+
}
197+
198+
private static List<String> expectedArsFromArgFile(String name) {
199+
List<String> arguments = new ArrayList<>();
200+
try (InputStream stream =
201+
requireNonNull(
202+
CommandLineTest.class.getResourceAsStream("/argfiles/" + name + "-expected.txt"));
203+
BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
204+
String line;
205+
while ((line = reader.readLine()) != null) {
206+
arguments.add(line);
207+
}
208+
} catch (IOException e) {
209+
Assertions.fail("Failed to read expected args from " + name + "argfile", e);
210+
}
211+
return arguments;
212+
}
213+
214+
private static List<String> flatten(Object... values) {
215+
List<String> result = new ArrayList<>();
216+
for (Object value : values) {
217+
if (value instanceof Collection) {
218+
result.addAll((Collection<? extends String>) value);
219+
} else {
220+
result.add(value.toString());
221+
}
222+
}
223+
return result;
224+
}
160225
}

0 commit comments

Comments
 (0)