Skip to content

Commit 5bd2af2

Browse files
author
Alan Bateman
committed
8307478: Implementation of Prepare to Restrict The Dynamic Loading of Agents
Reviewed-by: sspitsyn, cjplummer
1 parent 325940b commit 5bd2af2

File tree

21 files changed

+1125
-255
lines changed

21 files changed

+1125
-255
lines changed

make/data/hotspot-symbols/symbols-unix

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ JVM_NewArray
181181
JVM_NewInstanceFromConstructor
182182
JVM_NewMultiArray
183183
JVM_PhantomReferenceRefersTo
184+
JVM_PrintWarningAtDynamicAgentLoad
184185
JVM_RaiseSignal
185186
JVM_RawMonitorCreate
186187
JVM_RawMonitorDestroy

src/hotspot/share/include/jvm.h

+6
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,12 @@ JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide);
11641164
JNIEXPORT jint JNICALL
11651165
JVM_GetClassFileVersion(JNIEnv *env, jclass current);
11661166

1167+
/*
1168+
* Return JNI_TRUE if warnings are printed when agents are dynamically loaded.
1169+
*/
1170+
JNIEXPORT jboolean JNICALL
1171+
JVM_PrintWarningAtDynamicAgentLoad(void);
1172+
11671173
/*
11681174
* This structure is used by the launcher to get the default thread
11691175
* stack size from the VM using JNI_GetDefaultJavaVMInitArgs() with a

src/hotspot/share/prims/jvm.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -4024,3 +4024,10 @@ JVM_END
40244024
JVM_ENTRY(void, JVM_EnsureMaterializedForStackWalk_func(JNIEnv* env, jobject vthread, jobject value))
40254025
JVM_EnsureMaterializedForStackWalk(env, value);
40264026
JVM_END
4027+
4028+
/*
4029+
* Return JNI_TRUE if warnings are printed when agents are dynamically loaded.
4030+
*/
4031+
JVM_LEAF(jboolean, JVM_PrintWarningAtDynamicAgentLoad(void))
4032+
return (EnableDynamicAgentLoading && !FLAG_IS_CMDLINE(EnableDynamicAgentLoading)) ? JNI_TRUE : JNI_FALSE;
4033+
JVM_END

src/hotspot/share/prims/jvmti.xml

+11
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,17 @@ Agent_OnLoad_L(JavaVM *vm, char *options, void *reserved)</example>
640640
or implementation specific API, to attach to the running VM, and request it start a given
641641
agent.
642642
<p/>
643+
The VM prints a warning on the standard error stream for each agent that it attempts
644+
to start in the live phase. If an agent was previously started (in the <code>OnLoad</code>
645+
phase or in the live phase), then it is implementation specific as to whether a
646+
warning is printed when attempting to start the same agent a second or subsequent time.
647+
Warnings can be disabled by means of an implementation-specific command line option.
648+
<p/>
649+
<b>Implementation Note:</b> For the HotSpot VM, the VM option
650+
<code>-XX:+EnableDynamicAgentLoading</code> is used to opt-in to allow dynamic loading
651+
of agents in the live phase. This option suppresses the warning to standard error when
652+
starting an agent in the live phase.
653+
<p/>
643654
If an agent is started during the live phase then its agent library
644655
must export a start-up function
645656
with the following prototype:

src/hotspot/share/prims/jvmtiAgent.cpp

+20-3
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@
3030
#include "jvmtifiles/jvmtiEnv.hpp"
3131
#include "prims/jvmtiEnvBase.hpp"
3232
#include "prims/jvmtiExport.hpp"
33+
#include "prims/jvmtiAgentList.hpp"
3334
#include "runtime/arguments.hpp"
3435
#include "runtime/handles.inline.hpp"
3536
#include "runtime/interfaceSupport.inline.hpp"
3637
#include "runtime/java.hpp"
3738
#include "runtime/jniHandles.hpp"
39+
#include "runtime/globals_extension.hpp"
3840
#include "runtime/os.inline.hpp"
3941
#include "runtime/thread.inline.hpp"
42+
#include "utilities/defaultStream.hpp"
4043

4144
static inline const char* copy_string(const char* str) {
4245
return str != nullptr ? os::strdup(str, mtServiceability) : nullptr;
@@ -260,9 +263,9 @@ static void assert_preload(const JvmtiAgent* agent) {
260263

261264
// Check for a statically linked-in agent, i.e. in the executable.
262265
// This should be the first function called when loading an agent. It is a bit special:
263-
// For statically linked agents we cant't rely on os_lib == nullptr because
266+
// For statically linked agents we can't rely on os_lib == nullptr because
264267
// statically linked agents could have a handle of RTLD_DEFAULT which == 0 on some platforms.
265-
// If this function returns true, then agent->is_static_lib().&& agent->is_loaded().
268+
// If this function returns true, then agent->is_static_lib() && agent->is_loaded().
266269
static bool load_agent_from_executable(JvmtiAgent* agent, const char* on_load_symbols[], size_t num_symbol_entries) {
267270
DEBUG_ONLY(assert_preload(agent);)
268271
assert(on_load_symbols != nullptr, "invariant");
@@ -483,6 +486,7 @@ extern "C" {
483486
}
484487

485488
// Loading the agent by invoking Agent_OnAttach.
489+
// This function is called before the agent is added to JvmtiAgentList.
486490
static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) {
487491
DEBUG_ONLY(assert_preload(agent);)
488492
assert(agent->is_dynamic(), "invariant");
@@ -491,7 +495,10 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) {
491495
const char* on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS;
492496
const size_t num_symbol_entries = ARRAY_SIZE(on_attach_symbols);
493497
void* library = nullptr;
494-
if (!load_agent_from_executable(agent, &on_attach_symbols[0], num_symbol_entries)) {
498+
bool previously_loaded;
499+
if (load_agent_from_executable(agent, &on_attach_symbols[0], num_symbol_entries)) {
500+
previously_loaded = JvmtiAgentList::is_static_lib_loaded(agent->name());
501+
} else {
495502
library = load_library(agent, &on_attach_symbols[0], num_symbol_entries, /* vm_exit_on_error */ false);
496503
if (library == nullptr) {
497504
st->print_cr("%s was not loaded.", agent->name());
@@ -503,7 +510,17 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) {
503510
agent->set_os_lib_path(&buffer[0]);
504511
agent->set_os_lib(library);
505512
agent->set_loaded();
513+
previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(library);
514+
}
515+
516+
// Print warning if agent was not previously loaded and EnableDynamicAgentLoading not enabled on the command line.
517+
if (!previously_loaded && !FLAG_IS_CMDLINE(EnableDynamicAgentLoading) && !agent->is_instrument_lib()) {
518+
jio_fprintf(defaultStream::error_stream(),
519+
"WARNING: A JVM TI agent has been loaded dynamically (%s)\n"
520+
"WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning\n"
521+
"WARNING: Dynamic loading of agents will be disallowed by default in a future release\n", agent->name());
506522
}
523+
507524
assert(agent->is_loaded(), "invariant");
508525
// The library was loaded so we attempt to lookup and invoke the Agent_OnAttach function.
509526
OnAttachEntry_t on_attach_entry = CAST_TO_FN_PTR(OnAttachEntry_t,

src/hotspot/share/prims/jvmtiAgentList.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,30 @@ void JvmtiAgentList::unload_agents() {
220220
}
221221
}
222222

223+
// Return true if a statically linked agent is on the list
224+
bool JvmtiAgentList::is_static_lib_loaded(const char* name) {
225+
JvmtiAgentList::Iterator it = JvmtiAgentList::agents();
226+
while (it.has_next()) {
227+
JvmtiAgent* const agent = it.next();
228+
if (agent->is_static_lib() && strcmp(agent->name(), name) == 0) {
229+
return true;
230+
}
231+
}
232+
return false;
233+
}
234+
235+
// Return true if a agent library on the list
236+
bool JvmtiAgentList::is_dynamic_lib_loaded(void* os_lib) {
237+
JvmtiAgentList::Iterator it = JvmtiAgentList::agents();
238+
while (it.has_next()) {
239+
JvmtiAgent* const agent = it.next();
240+
if (!agent->is_static_lib() && agent->os_lib() == os_lib) {
241+
return true;
242+
}
243+
}
244+
return false;
245+
}
246+
223247
static bool match(JvmtiEnv* env, const JvmtiAgent* agent, const void* os_module_address) {
224248
assert(env != nullptr, "invariant");
225249
assert(agent != nullptr, "invariant");

src/hotspot/share/prims/jvmtiAgentList.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class JvmtiAgentList : AllStatic {
7676
static void load_xrun_agents() NOT_JVMTI_RETURN;
7777
static void unload_agents() NOT_JVMTI_RETURN;
7878

79+
static bool is_static_lib_loaded(const char* name);
80+
static bool is_dynamic_lib_loaded(void* os_lib);
81+
7982
static JvmtiAgent* lookup(JvmtiEnv* env, void* f_ptr);
8083

8184
static Iterator agents() NOT_JVMTI({ Iterator it; return it; });

0 commit comments

Comments
 (0)