Skip to content

Commit 21fcec0

Browse files
cost0muchPaul Hohensee
authored andcommitted
8325530: Vague error message when com.sun.tools.attach.VirtualMachine fails to load agent library
Backport-of: fc67c2b4f17216d4adcc0825d0f378ae4f150025
1 parent ff99698 commit 21fcec0

File tree

6 files changed

+134
-41
lines changed

6 files changed

+134
-41
lines changed

src/hotspot/share/prims/jvmtiAgentList.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2024, 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
@@ -124,11 +124,11 @@ void JvmtiAgentList::add(JvmtiAgent* agent) {
124124
} while (Atomic::cmpxchg(&_list, next, agent) != next);
125125
}
126126

127-
void JvmtiAgentList::add(const char* name, char* options, bool absolute_path) {
127+
void JvmtiAgentList::add(const char* name, const char* options, bool absolute_path) {
128128
add(new JvmtiAgent(name, options, absolute_path));
129129
}
130130

131-
void JvmtiAgentList::add_xrun(const char* name, char* options, bool absolute_path) {
131+
void JvmtiAgentList::add_xrun(const char* name, const char* options, bool absolute_path) {
132132
JvmtiAgent* agent = new JvmtiAgent(name, options, absolute_path);
133133
agent->set_xrun();
134134
add(agent);
@@ -198,18 +198,14 @@ void JvmtiAgentList::load_xrun_agents() {
198198
}
199199

200200
// Invokes Agent_OnAttach for agents loaded dynamically during runtime.
201-
jint JvmtiAgentList::load_agent(const char* agent_name, const char* absParam,
202-
const char* options, outputStream* st) {
203-
// The abs parameter should be "true" or "false"
204-
const bool is_absolute_path = (absParam != nullptr) && (strcmp(absParam, "true") == 0);
201+
void JvmtiAgentList::load_agent(const char* agent_name, bool is_absolute_path,
202+
const char* options, outputStream* st) {
205203
JvmtiAgent* const agent = new JvmtiAgent(agent_name, options, is_absolute_path, /* dynamic agent */ true);
206204
if (agent->load(st)) {
207205
add(agent);
208206
} else {
209207
delete agent;
210208
}
211-
// Agent_OnAttach executed so completion status is JNI_OK
212-
return JNI_OK;
213209
}
214210

215211
// Send any Agent_OnUnload notifications

src/hotspot/share/prims/jvmtiAgentList.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2024, 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
@@ -64,14 +64,15 @@ class JvmtiAgentList : AllStatic {
6464
static void initialize();
6565
static void convert_xrun_agents();
6666

67-
public:
6867
static void add(JvmtiAgent* agent) NOT_JVMTI_RETURN;
69-
static void add(const char* name, char* options, bool absolute_path) NOT_JVMTI_RETURN;
70-
static void add_xrun(const char* name, char* options, bool absolute_path) NOT_JVMTI_RETURN;
68+
69+
public:
70+
static void add(const char* name, const char* options, bool absolute_path) NOT_JVMTI_RETURN;
71+
static void add_xrun(const char* name, const char* options, bool absolute_path) NOT_JVMTI_RETURN;
7172

7273
static void load_agents() NOT_JVMTI_RETURN;
73-
static jint load_agent(const char* agent, const char* absParam,
74-
const char* options, outputStream* st) NOT_JVMTI_RETURN_(0);
74+
static void load_agent(const char* agent, bool is_absolute_path,
75+
const char* options, outputStream* st) NOT_JVMTI_RETURN;
7576
static void load_xrun_agents() NOT_JVMTI_RETURN;
7677
static void unload_agents() NOT_JVMTI_RETURN;
7778

src/hotspot/share/services/attachListener.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,12 @@ static jint load_agent(AttachOperation* op, outputStream* out) {
135135
}
136136
}
137137

138-
return JvmtiAgentList::load_agent(agent, absParam, options, out);
138+
// The abs parameter should be "true" or "false".
139+
const bool is_absolute_path = (absParam != nullptr) && (strcmp(absParam, "true") == 0);
140+
JvmtiAgentList::load_agent(agent, is_absolute_path, options, out);
141+
142+
// Agent_OnAttach result or error message is written to 'out'.
143+
return JNI_OK;
139144
}
140145

141146
// Implementation of "properties" command.

src/hotspot/share/services/diagnosticCommand.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
304304

305305
if (is_java_agent) {
306306
if (_option.value() == nullptr) {
307-
JvmtiAgentList::load_agent("instrument", "false", _libpath.value(), output());
307+
JvmtiAgentList::load_agent("instrument", false, _libpath.value(), output());
308308
} else {
309309
size_t opt_len = strlen(_libpath.value()) + strlen(_option.value()) + 2;
310310
if (opt_len > 4096) {
@@ -321,12 +321,12 @@ void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
321321
}
322322

323323
jio_snprintf(opt, opt_len, "%s=%s", _libpath.value(), _option.value());
324-
JvmtiAgentList::load_agent("instrument", "false", opt, output());
324+
JvmtiAgentList::load_agent("instrument", false, opt, output());
325325

326326
os::free(opt);
327327
}
328328
} else {
329-
JvmtiAgentList::load_agent(_libpath.value(), "true", _option.value(), output());
329+
JvmtiAgentList::load_agent(_libpath.value(), true, _option.value(), output());
330330
}
331331
}
332332

src/jdk.attach/share/classes/sun/tools/attach/HotSpotVirtualMachine.java

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2024, 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
@@ -96,22 +96,30 @@ private void loadAgentLibrary(String agentLibrary, boolean isAbsolute, String op
9696
}
9797

9898
String msgPrefix = "return code: ";
99-
InputStream in = execute("load",
100-
agentLibrary,
101-
isAbsolute ? "true" : "false",
102-
options);
103-
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
104-
String result = reader.readLine();
105-
if (result == null) {
99+
String errorMsg = "Failed to load agent library";
100+
try {
101+
InputStream in = execute("load",
102+
agentLibrary,
103+
isAbsolute ? "true" : "false",
104+
options);
105+
String result = readErrorMessage(in);
106+
if (result.isEmpty()) {
106107
throw new AgentLoadException("Target VM did not respond");
107108
} else if (result.startsWith(msgPrefix)) {
108109
int retCode = Integer.parseInt(result.substring(msgPrefix.length()));
109110
if (retCode != 0) {
110111
throw new AgentInitializationException("Agent_OnAttach failed", retCode);
111112
}
112113
} else {
113-
throw new AgentLoadException(result);
114+
if (!result.isEmpty()) {
115+
errorMsg += ": " + result;
116+
}
117+
throw new AgentLoadException(errorMsg);
114118
}
119+
} catch (AttachOperationFailedException ex) {
120+
// execute() throws AttachOperationFailedException if attach agent reported error.
121+
// Convert it to AgentLoadException.
122+
throw new AgentLoadException(errorMsg + ": " + ex.getMessage());
115123
}
116124
}
117125

@@ -364,6 +372,9 @@ String readErrorMessage(InputStream in) throws IOException {
364372
StringBuilder message = new StringBuilder();
365373
BufferedReader br = new BufferedReader(new InputStreamReader(in));
366374
while ((s = br.readLine()) != null) {
375+
if (message.length() > 0) {
376+
message.append(' ');
377+
}
367378
message.append(s);
368379
}
369380
return message.toString();
@@ -399,20 +410,10 @@ void processCompletionStatus(IOException ioe, String cmd, InputStream sis) throw
399410
throw new IOException("Protocol mismatch with target VM");
400411
}
401412

402-
// Special-case the "load" command so that the right exception is
403-
// thrown.
404-
if (cmd.equals("load")) {
405-
String msg = "Failed to load agent library";
406-
if (!message.isEmpty()) {
407-
msg += ": " + message;
408-
}
409-
throw new AgentLoadException(msg);
410-
} else {
411-
if (message.isEmpty()) {
412-
message = "Command failed in target VM";
413-
}
414-
throw new AttachOperationFailedException(message);
413+
if (message.isEmpty()) {
414+
message = "Command failed in target VM";
415415
}
416+
throw new AttachOperationFailedException(message);
416417
}
417418
}
418419

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2024, 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 8325530
27+
* @summary Test that failed VirtualMachine.loadAgentPath/loadAgentLibrary reports detailed reason
28+
* @requires vm.jvmti
29+
* @modules jdk.attach
30+
* @library /test/lib
31+
* @run driver FailedLoadAgentTest
32+
*/
33+
34+
import java.nio.file.Path;
35+
import com.sun.tools.attach.AgentLoadException;
36+
import com.sun.tools.attach.VirtualMachine;
37+
38+
import jdk.test.lib.Platform;
39+
import jdk.test.lib.Utils;
40+
import jdk.test.lib.apps.LingeredApp;
41+
42+
public class FailedLoadAgentTest {
43+
private static final String jvmtiAgentLib = "FailedLoadAgentTestNotExists";
44+
private static final String jvmtiAgentPath = getLibPath(jvmtiAgentLib);
45+
46+
private static String getLibPath(String libName) {
47+
String fullName = Platform.buildSharedLibraryName(libName);
48+
return Path.of(Utils.TEST_NATIVE_PATH, fullName).toAbsolutePath().toString();
49+
}
50+
51+
private interface TestAction {
52+
void test() throws Exception;
53+
}
54+
55+
private static void test(TestAction action) throws Exception {
56+
try {
57+
action.test();
58+
throw new RuntimeException("AgentLoadException not thrown");
59+
} catch (AgentLoadException ex) {
60+
System.out.println("AgentLoadException thrown as expected:");
61+
ex.printStackTrace(System.out);
62+
String msg = ex.getMessage();
63+
// Attach agent prints general "<agent> was not loaded." message on error.
64+
// But additionally we expect detailed message with the reason.
65+
String parts[] = msg.split("was not loaded.");
66+
if (parts.length < 2 || parts[1].isEmpty()) {
67+
throw new RuntimeException("AgentLoadException message is vague");
68+
}
69+
}
70+
}
71+
72+
public static void main(String[] args) throws Exception {
73+
LingeredApp theApp = null;
74+
try {
75+
theApp = new LingeredApp();
76+
LingeredApp.startApp(theApp, "-XX:+EnableDynamicAgentLoading");
77+
78+
VirtualMachine vm = VirtualMachine.attach(Long.toString(theApp.getPid()));
79+
80+
// absolute path
81+
test(() -> vm.loadAgentPath(jvmtiAgentPath));
82+
// relative path
83+
test(() -> vm.loadAgentLibrary(jvmtiAgentLib));
84+
85+
} finally {
86+
LingeredApp.stopApp(theApp);
87+
}
88+
}
89+
90+
}

0 commit comments

Comments
 (0)