Skip to content

Commit 8554405

Browse files
authored
Abort bootstrap JDK tool tests (#11134) (#11147)
test: Aborting on bootstrap JDK tool tests test: Smoke tests on JDK tools test: spotless and codenarc fix: Additional JDK 8 tools spotted by the smoke test Those appear to be JDK 8 specific (cherry picked from commit 8b1580f)
1 parent 8a1de7d commit 8554405

File tree

6 files changed

+540
-33
lines changed

6 files changed

+540
-33
lines changed

dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -216,41 +216,74 @@ private static boolean alreadyInitialized() {
216216
return false;
217217
}
218218

219+
/**
220+
* Returns {@code true} if the JVM is running a JDK diagnostic/development tool rather than a user
221+
* application, in which case the agent should abort early.
222+
*
223+
* <p><b>How to discover new entries when a tool is missed:</b>
224+
*
225+
* <ol>
226+
* <li>Build a minimal javaagent JAR whose {@code premain} prints {@code
227+
* System.getProperty("jdk.module.main")} and {@code System.getProperty("sun.java.command")}
228+
* then calls {@code System.exit(0)}.
229+
* <li>For <b>JDK 9+ tools</b>, inject it via {@code JAVA_TOOL_OPTIONS}:
230+
* <pre>JAVA_TOOL_OPTIONS="-javaagent:/path/to/agent.jar" $JAVA_HOME/bin/&lt;tool&gt;</pre>
231+
* The value of {@code jdk.module.main} is the module name to add to the first switch.
232+
* <li>For <b>JDK 8 tools</b> (or non-modular IBM/OpenJ9 tools), inject the same way; the value
233+
* of {@code sun.java.command} (up to the first space) is the main-class name to add to the
234+
* second switch.
235+
* </ol>
236+
*
237+
* <p>Native binaries (e.g. {@code jitserver}, {@code asprof}) report both properties as {@code
238+
* null} and are automatically ignored — no switch entry needed for them.
239+
*/
219240
static boolean isJdkTool() {
220241
String moduleMain = SystemProperties.get("jdk.module.main");
221-
if (null != moduleMain && !moduleMain.isEmpty() && moduleMain.charAt(0) == 'j') {
222-
switch (moduleMain) {
223-
case "java.base": // keytool
224-
case "java.corba":
225-
case "java.desktop":
226-
case "java.rmi":
227-
case "java.scripting":
228-
case "java.security.jgss":
229-
case "jdk.aot":
230-
case "jdk.compiler":
231-
case "jdk.dev":
232-
case "jdk.hotspot.agent":
233-
case "jdk.httpserver":
234-
case "jdk.jartool":
235-
case "jdk.javadoc":
236-
case "jdk.jcmd":
237-
case "jdk.jconsole":
238-
case "jdk.jdeps":
239-
case "jdk.jdi":
240-
case "jdk.jfr":
241-
case "jdk.jlink":
242-
case "jdk.jpackage":
243-
case "jdk.jshell":
244-
case "jdk.jstatd":
245-
case "jdk.jvmstat.rmi":
246-
case "jdk.pack":
247-
case "jdk.pack200":
248-
case "jdk.policytool":
249-
case "jdk.rmic":
250-
case "jdk.scripting.nashorn.shell":
251-
case "jdk.xml.bind":
252-
case "jdk.xml.ws":
253-
return true;
242+
if (null != moduleMain && !moduleMain.isEmpty()) {
243+
char firstChar = moduleMain.charAt(0);
244+
if (firstChar == 'j') {
245+
// Standard JDK 9+ module-based tools (module names start with 'java.' or 'jdk.')
246+
switch (moduleMain) {
247+
case "java.base": // keytool
248+
case "java.corba":
249+
case "java.desktop":
250+
case "java.rmi":
251+
case "java.scripting":
252+
case "java.security.jgss":
253+
case "jdk.aot":
254+
case "jdk.compiler":
255+
case "jdk.dev":
256+
case "jdk.hotspot.agent":
257+
case "jdk.httpserver":
258+
case "jdk.jartool":
259+
case "jdk.javadoc":
260+
case "jdk.jcmd":
261+
case "jdk.jconsole":
262+
case "jdk.jdeps":
263+
case "jdk.jdi":
264+
case "jdk.jfr":
265+
case "jdk.jlink":
266+
case "jdk.jpackage":
267+
case "jdk.jshell":
268+
case "jdk.jstatd":
269+
case "jdk.jvmstat.rmi":
270+
case "jdk.pack":
271+
case "jdk.pack200":
272+
case "jdk.policytool":
273+
case "jdk.rmic":
274+
case "jdk.scripting.nashorn.shell":
275+
case "jdk.xml.bind":
276+
case "jdk.xml.ws":
277+
return true;
278+
}
279+
} else if (firstChar == 'o') {
280+
// OpenJ9 / Semeru 11+ module-based tools (module names start with 'openj9.')
281+
switch (moduleMain) {
282+
case "openj9.dtfj": // jextract, jpackcore
283+
case "openj9.dtfjview": // jdmpview
284+
case "openj9.traceformat": // traceformat
285+
return true;
286+
}
254287
}
255288
}
256289
// Handles JDK 8 tools (IBM J9 and standard JDK 8 vendors)
@@ -267,9 +300,18 @@ static boolean isJdkTool() {
267300
case "com.ibm.security.krb5.internal.tools.Klist": // klist
268301
case "com.ibm.security.krb5.internal.tools.Ktab": // ktab
269302
case "com.ibm.jvm.dtfjview.DTFJView": // jdmpview
303+
case "com.ibm.jvm.j9.dump.extract.Main": // jextract
304+
case "com.ibm.gsk.ikeyman.Ikeyman": // ikeyman
270305
case "com.ibm.gsk.ikeyman.ikeycmd": // ikeycmd
271306
case "com.ibm.CosNaming.TransientNameServer": // tnameserv
272307
case "com.ibm.idl.toJavaPortable.Compile": // idlj
308+
// OpenJ9 / Semeru 8 specific tool main classes (OpenJ9 reimplementation of HotSpot tools)
309+
case "openj9.tools.attach.diagnostics.tools.Jcmd": // jcmd
310+
case "openj9.tools.attach.diagnostics.tools.Jps": // jps
311+
case "openj9.tools.attach.diagnostics.tools.Jstat": // jstat
312+
case "openj9.tools.attach.diagnostics.tools.Jmap": // jmap
313+
case "openj9.tools.attach.diagnostics.tools.Jstack": // jstack
314+
case "com.ibm.jvm.TraceFormat": // traceformat
273315
// Standard JDK 8 tool main classes (shared by IBM J9 and Oracle/OpenJDK 8)
274316
case "sun.tools.jar.Main": // jar
275317
case "com.sun.tools.javac.Main": // javac
@@ -292,6 +334,7 @@ static boolean isJdkTool() {
292334
case "com.sun.tools.internal.xjc.Driver": // xjc
293335
case "com.sun.tools.internal.jxc.SchemaGenerator": // schemagen
294336
case "com.sun.tools.script.shell.Main": // jrunscript
337+
case "jdk.nashorn.tools.Shell": // jjs (Nashorn JS shell, JDK 8)
295338
case "sun.tools.jconsole.JConsole": // jconsole
296339
case "sun.applet.Main": // appletviewer
297340
case "com.sun.corba.se.impl.naming.cosnaming.TransientNameServer": // tnameserv
@@ -310,6 +353,8 @@ static boolean isJdkTool() {
310353
case "jdk.jfr.internal.tool.Main": // jfr, backported to OpenJDK 8 in 8u262 (JEP 328
311354
// backport, July 2020)
312355
case "sun.jvm.hotspot.jdi.SADebugServer": // jsadebugd
356+
case "sun.jvm.hotspot.HSDB": // hsdb (HotSpot SA GUI debugger, JDK 8)
357+
case "sun.jvm.hotspot.CLHSDB": // clhsdb (HotSpot SA command-line debugger, JDK 8)
313358
return true;
314359
}
315360
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package datadog.trace.bootstrap;
2+
3+
import static org.junit.jupiter.api.Assertions.assertFalse;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import org.junit.jupiter.api.AfterEach;
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.params.ParameterizedTest;
10+
import org.junit.jupiter.params.provider.ValueSource;
11+
12+
class AgentBootstrapAbortOnJdkToolTest {
13+
14+
private String savedModuleMain;
15+
private String savedJavaCommand;
16+
17+
@BeforeEach
18+
void saveAndClearProperties() {
19+
savedModuleMain = System.clearProperty("jdk.module.main");
20+
savedJavaCommand = System.clearProperty("sun.java.command");
21+
}
22+
23+
@AfterEach
24+
void restoreProperties() {
25+
restoreProperty("jdk.module.main", savedModuleMain);
26+
restoreProperty("sun.java.command", savedJavaCommand);
27+
}
28+
29+
private static void restoreProperty(String key, String previousValue) {
30+
if (previousValue == null) {
31+
System.clearProperty(key);
32+
} else {
33+
System.setProperty(key, previousValue);
34+
}
35+
}
36+
37+
@Test
38+
void notAJdkToolWhenNoPropertiesSet() {
39+
assertFalse(AgentBootstrap.isJdkTool());
40+
}
41+
42+
@Test
43+
void notAJdkToolWhenCommandIsNotAKnownTool() {
44+
System.setProperty("sun.java.command", "com.example.MyApplication");
45+
assertFalse(AgentBootstrap.isJdkTool());
46+
}
47+
48+
@Test
49+
void notAJdkToolWhenModuleMainIsNotAKnownTool() {
50+
System.setProperty("jdk.module.main", "com.example.myapp");
51+
assertFalse(AgentBootstrap.isJdkTool());
52+
}
53+
54+
@ParameterizedTest
55+
@ValueSource(
56+
strings = {
57+
// Standard JDK 9+ module-based tools
58+
"java.base", // keytool
59+
"jdk.compiler", // javac
60+
"jdk.jartool", // jar
61+
"jdk.javadoc", // javadoc
62+
"jdk.jcmd", // jcmd
63+
"jdk.jconsole", // jconsole
64+
"jdk.jshell", // jshell
65+
"jdk.jfr", // jfr (JDK 9+)
66+
// OpenJ9 / Semeru 11+ module-based tools
67+
"openj9.dtfj", // jextract, jpackcore
68+
"openj9.dtfjview", // jdmpview
69+
"openj9.traceformat", // traceformat
70+
})
71+
void isJdkToolByModuleMain(String moduleMain) {
72+
System.setProperty("jdk.module.main", moduleMain);
73+
assertTrue(AgentBootstrap.isJdkTool());
74+
}
75+
76+
@ParameterizedTest
77+
@ValueSource(
78+
strings = {
79+
// IBM J9 JDK 8 specific tool main classes
80+
"com.ibm.crypto.tools.KeyTool", // keytool
81+
"com.ibm.security.krb5.internal.tools.Kinit", // kinit
82+
"com.ibm.security.krb5.internal.tools.Klist", // klist
83+
"com.ibm.security.krb5.internal.tools.Ktab", // ktab
84+
"com.ibm.jvm.dtfjview.DTFJView", // jdmpview
85+
"com.ibm.jvm.j9.dump.extract.Main", // jextract
86+
"com.ibm.gsk.ikeyman.Ikeyman", // ikeyman
87+
"com.ibm.gsk.ikeyman.ikeycmd", // ikeycmd
88+
"com.ibm.CosNaming.TransientNameServer", // tnameserv
89+
"com.ibm.idl.toJavaPortable.Compile", // idlj
90+
// OpenJ9 / Semeru 8 specific tool main classes (OpenJ9 reimplementation of HotSpot tools)
91+
"openj9.tools.attach.diagnostics.tools.Jcmd", // jcmd
92+
"openj9.tools.attach.diagnostics.tools.Jps", // jps
93+
"openj9.tools.attach.diagnostics.tools.Jstat", // jstat
94+
"openj9.tools.attach.diagnostics.tools.Jmap", // jmap
95+
"openj9.tools.attach.diagnostics.tools.Jstack", // jstack
96+
"com.ibm.jvm.TraceFormat", // traceformat
97+
// Standard JDK 8 tool main classes (Corretto 8 / OpenJDK 8)
98+
"sun.tools.jar.Main", // jar
99+
"com.sun.tools.javac.Main", // javac
100+
"com.sun.tools.javadoc.Main", // javadoc
101+
"com.sun.tools.javap.Main", // javap
102+
"com.sun.tools.javah.Main", // javah
103+
"sun.security.tools.keytool.Main", // keytool
104+
"sun.security.tools.jarsigner.Main", // jarsigner
105+
"sun.security.tools.policytool.PolicyTool", // policytool
106+
"com.sun.tools.example.debug.tty.TTY", // jdb
107+
"com.sun.tools.jdeps.Main", // jdeps
108+
"sun.rmi.rmic.Main", // rmic
109+
"sun.rmi.registry.RegistryImpl", // rmiregistry
110+
"sun.rmi.server.Activation", // rmid
111+
"com.sun.tools.extcheck.Main", // extcheck
112+
"sun.tools.serialver.SerialVer", // serialver
113+
"sun.tools.native2ascii.Main", // native2ascii
114+
"com.sun.tools.internal.ws.WsGen", // wsgen
115+
"com.sun.tools.internal.ws.WsImport", // wsimport
116+
"com.sun.tools.internal.xjc.Driver", // xjc
117+
"com.sun.tools.internal.jxc.SchemaGenerator", // schemagen
118+
"com.sun.tools.script.shell.Main", // jrunscript
119+
"sun.tools.jconsole.JConsole", // jconsole
120+
"sun.applet.Main", // appletviewer
121+
"com.sun.corba.se.impl.naming.cosnaming.TransientNameServer", // tnameserv
122+
"com.sun.tools.corba.se.idl.toJavaPortable.Compile", // idlj
123+
"com.sun.corba.se.impl.activation.ORBD", // orbd
124+
"com.sun.corba.se.impl.activation.ServerTool", // servertool
125+
"sun.tools.jps.Jps", // jps
126+
"sun.tools.jstack.JStack", // jstack
127+
"sun.tools.jmap.JMap", // jmap
128+
"sun.tools.jinfo.JInfo", // jinfo
129+
"com.sun.tools.hat.Main", // jhat
130+
"sun.tools.jstat.Jstat", // jstat
131+
"sun.tools.jstatd.Jstatd", // jstatd
132+
"sun.tools.jcmd.JCmd", // jcmd
133+
"jdk.jfr.internal.tool.Main", // jfr (OpenJDK 8u262+ backport)
134+
"sun.jvm.hotspot.jdi.SADebugServer", // jsadebugd
135+
"jdk.nashorn.tools.Shell", // jjs (Nashorn JS shell, JDK 8)
136+
"sun.jvm.hotspot.HSDB", // hsdb (HotSpot SA GUI debugger, JDK 8)
137+
"sun.jvm.hotspot.CLHSDB", // clhsdb (HotSpot SA command-line debugger, JDK 8)
138+
})
139+
void isJdkToolByCommand(String mainClass) {
140+
System.setProperty("sun.java.command", mainClass);
141+
assertTrue(AgentBootstrap.isJdkTool());
142+
}
143+
144+
@Test
145+
void isJdkToolWhenCommandIncludesArguments() {
146+
System.setProperty("sun.java.command", "com.ibm.crypto.tools.KeyTool -list -v");
147+
assertTrue(AgentBootstrap.isJdkTool());
148+
}
149+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apply from: "$rootDir/gradle/java.gradle"
2+
description = 'JDK Tool Abort Smoke Tests'
3+
4+
dependencies {
5+
testImplementation project(':dd-smoke-tests')
6+
}

0 commit comments

Comments
 (0)