Skip to content

Commit 8692058

Browse files
author
duke
committed
Backport 2a8cbd944ba4d8896e48181e396c65f70e5aa215
1 parent ceac6c7 commit 8692058

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

src/hotspot/share/prims/jvmtiAgentList.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ void JvmtiAgentList::load_xrun_agents() {
201201
// Invokes Agent_OnAttach for agents loaded dynamically during runtime.
202202
void JvmtiAgentList::load_agent(const char* agent_name, bool is_absolute_path,
203203
const char* options, outputStream* st) {
204+
if (JvmtiEnvBase::get_phase() != JVMTI_PHASE_LIVE) {
205+
st->print_cr("Dynamic agent loading is only permitted in the live phase");
206+
return;
207+
}
208+
204209
JvmtiAgent* const agent = new JvmtiAgent(agent_name, options, is_absolute_path, /* dynamic agent */ true);
205210
if (agent->load(st)) {
206211
add(agent);
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2025, 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+
import com.sun.tools.attach.VirtualMachine;
25+
import com.sun.tools.attach.AgentLoadException;
26+
27+
import org.junit.jupiter.api.Test;
28+
import org.junit.jupiter.api.BeforeAll;
29+
import org.junit.jupiter.api.AfterAll;
30+
31+
import java.io.File;
32+
import java.io.InputStream;
33+
import java.io.OutputStream;
34+
import java.util.concurrent.TimeUnit;
35+
import jdk.test.lib.dcmd.PidJcmdExecutor;
36+
import jdk.test.lib.process.OutputAnalyzer;
37+
import jdk.test.lib.process.ProcessTools;
38+
import jdk.test.lib.Utils;
39+
40+
/*
41+
* @test EarlyDynamicLoad
42+
* @summary Test that dynamic attach fails gracefully when the JVM is not in live phase.
43+
* @requires vm.jvmti
44+
* @library /test/lib
45+
* @run junit EarlyDynamicLoad
46+
*/
47+
public class EarlyDynamicLoad {
48+
private static final String EXPECTED_MESSAGE = "Dynamic agent loading is only permitted in the live phase";
49+
50+
private static Process child;
51+
52+
@BeforeAll
53+
static void startAndWaitChild() throws Exception {
54+
child = ProcessTools.createTestJavaProcessBuilder(
55+
"-XX:+StartAttachListener",
56+
"-agentpath:" + Utils.TEST_NATIVE_PATH + File.separator + System.mapLibraryName("EarlyDynamicLoad"),
57+
"--version").start();
58+
59+
// Wait until the process enters VMStartCallback
60+
try (InputStream is = child.getInputStream()) {
61+
is.read();
62+
}
63+
}
64+
65+
@AfterAll
66+
static void stopChild() throws Exception {
67+
try (OutputStream os = child.getOutputStream()) {
68+
os.write(0);
69+
}
70+
71+
if (!child.waitFor(5, TimeUnit.SECONDS)) {
72+
child.destroyForcibly();
73+
throw new AssertionError("Timed out while waiting child process to complete");
74+
}
75+
76+
OutputAnalyzer analyzer = new OutputAnalyzer(child);
77+
analyzer.shouldHaveExitValue(0);
78+
analyzer.stderrShouldBeEmpty();
79+
}
80+
81+
@Test
82+
public void virtualMachine() throws Exception {
83+
try {
84+
VirtualMachine vm = VirtualMachine.attach(String.valueOf(child.pid()));
85+
vm.loadAgent("some.jar");
86+
vm.detach();
87+
throw new AssertionError("Should have failed with AgentLoadException");
88+
} catch(AgentLoadException exception) {
89+
if (!exception.getMessage().contains(EXPECTED_MESSAGE)) {
90+
throw new AssertionError("Unexpected error message", exception);
91+
}
92+
}
93+
}
94+
95+
@Test
96+
public void jcmd() throws Exception {
97+
PidJcmdExecutor executor = new PidJcmdExecutor(String.valueOf(child.pid()));
98+
OutputAnalyzer out = executor.execute("JVMTI.agent_load some.jar");
99+
100+
out.shouldHaveExitValue(0);
101+
out.stdoutShouldContain(EXPECTED_MESSAGE);
102+
}
103+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2025, 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+
#include <jvmti.h>
25+
#include <cstdio>
26+
#include <cstring>
27+
28+
extern "C" {
29+
30+
static void JNICALL VMStartCallback(jvmtiEnv* jvmti, JNIEnv* env) {
31+
putchar('1');
32+
fflush(stdout);
33+
getchar();
34+
}
35+
36+
JNIEXPORT int Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
37+
jvmtiEnv* jvmti;
38+
if (vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0) != JVMTI_ERROR_NONE) {
39+
fprintf(stderr, "JVMTI error occurred during GetEnv\n");
40+
return JNI_ERR;
41+
}
42+
43+
jvmtiEventCallbacks callbacks;
44+
memset(&callbacks, 0, sizeof(callbacks));
45+
callbacks.VMStart = VMStartCallback;
46+
47+
if (jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)) != JVMTI_ERROR_NONE) {
48+
fprintf(stderr, "JVMTI error occurred during SetEventCallbacks\n");
49+
return JNI_ERR;
50+
}
51+
if (jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, nullptr) != JVMTI_ERROR_NONE) {
52+
fprintf(stderr, "JVMTI error occurred during SetEventNotificationMode\n");
53+
return JNI_ERR;
54+
}
55+
56+
return JNI_OK;
57+
}
58+
59+
}

0 commit comments

Comments
 (0)