Skip to content

Commit

Permalink
Merge pull request #17932 from JasonFengJ9/jep451
Browse files Browse the repository at this point in the history
Implement JEP 451: Prepare to Disallow the Dynamic Loading of Agents
  • Loading branch information
keithc-ca authored Aug 12, 2023
2 parents 67e11c6 + c8ab4b6 commit 58047f8
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class DiagnosticUtils {
private static final String FORMAT_PREFIX = " Format: "; //$NON-NLS-1$

@SuppressWarnings("nls")
private static final String HEAP_DUMP_OPTION_HELP = " [request=<options>] [opts=<options] [<file path>]%n"
private static final String HEAP_DUMP_OPTION_HELP = " [request=<options>] [opts=<options>] [<file path>]%n"
+ " Set optional request= and opts= -Xdump options. The order of the parameters does not matter.%n";

@SuppressWarnings("nls")
Expand Down Expand Up @@ -100,7 +100,10 @@ public class DiagnosticUtils {
* Get JVM statistics
*/
private static final String DIAGNOSTICS_STAT_CLASS = "jstat.class"; //$NON-NLS-1$


// load JVMTI agent
private static final String DIAGNOSTICS_LOAD_JVMTI_AGENT = "JVMTI.agent_load"; //$NON-NLS-1$

/**
* Key for the command sent to executeDiagnosticCommand()
*/
Expand Down Expand Up @@ -354,7 +357,27 @@ private static DiagnosticProperties getJstatClass(String diagnosticCommand) {
bufferPrinter.flush();
return DiagnosticProperties.makeStringResult(buffer.toString());
}


@SuppressWarnings("nls")
private static DiagnosticProperties loadJVMTIAgent(String diagnosticCommand) {
DiagnosticProperties result;
String[] parts = diagnosticCommand.split(DIAGNOSTICS_OPTION_SEPARATOR);
// parts[0] is already verified as DIAGNOSTICS_LOAD_JVMTI_AGENT since we are here
if (parts.length < 2) {
result = DiagnosticProperties.makeErrorProperties("Too few arguments, the absolute path of the agent is required: " + diagnosticCommand);
} else if (parts.length > 3) {
result = DiagnosticProperties.makeErrorProperties("Command not recognized due to more than 3 arguments: " + diagnosticCommand);
} else {
String attachError = Attachment.loadAgentLibrary(parts[1], (parts.length == 3) ? parts[2] : "", false);
if (attachError == null) {
result = DiagnosticProperties.makeStringResult(DIAGNOSTICS_LOAD_JVMTI_AGENT + " succeeded");
} else {
result = DiagnosticProperties.makeStatusProperties(true, attachError);
}
}
return result;
}

private static DiagnosticProperties doHelp(String diagnosticCommand) {
String[] parts = diagnosticCommand.split(DIAGNOSTICS_OPTION_SEPARATOR);
/* print a list of the available commands */
Expand Down Expand Up @@ -416,7 +439,13 @@ private static DiagnosticProperties doHelp(String diagnosticCommand) {
private static final String DIAGNOSTICS_JSTAT_CLASS_HELP = "Show JVM classloader statistics.%n" //$NON-NLS-1$
+ FORMAT_PREFIX + DIAGNOSTICS_STAT_CLASS + "%n" //$NON-NLS-1$
+ "NOTE: this utility might significantly affect the performance of the target VM.%n"; //$NON-NLS-1$


@SuppressWarnings("nls")
private static final String DIAGNOSTICS_LOAD_JVMTI_AGENT_HELP = "Load JVMTI agent.%n"
+ FORMAT_PREFIX + DIAGNOSTICS_LOAD_JVMTI_AGENT + " <agentLibrary> [<agent option>]%n"
+ " agentLibrary: the absolute path of the agent%n"
+ " agent option: (Optional) the agent option string%n";

/* Initialize the command and help text tables */
static {
commandTable = new HashMap<>();
Expand Down Expand Up @@ -451,5 +480,8 @@ private static DiagnosticProperties doHelp(String diagnosticCommand) {

commandTable.put(DIAGNOSTICS_STAT_CLASS, DiagnosticUtils::getJstatClass);
helpTable.put(DIAGNOSTICS_STAT_CLASS, DIAGNOSTICS_JSTAT_CLASS_HELP);

commandTable.put(DIAGNOSTICS_LOAD_JVMTI_AGENT, DiagnosticUtils::loadJVMTIAgent);
helpTable.put(DIAGNOSTICS_LOAD_JVMTI_AGENT, DIAGNOSTICS_LOAD_JVMTI_AGENT_HELP);
}
}
13 changes: 9 additions & 4 deletions runtime/j9vm/javanextvmi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "bcverify_api.h"
#include "j9.h"
#include "j9cfg.h"
#include "jvminit.h"
#include "rommeth.h"
#include "ut_j9scar.h"
#include "util_api.h"
Expand Down Expand Up @@ -548,10 +549,14 @@ JVM_VirtualThreadHideFrames(JNIEnv *env, jobject vthread, jboolean hide)
JNIEXPORT jboolean JNICALL
JVM_PrintWarningAtDynamicAgentLoad()
{
/* A temporary implementation, an actual solution is provided via
* https://github.com/eclipse-openj9/openj9/issues/17500
*/
return JNI_TRUE;
jboolean result = JNI_TRUE;
J9JavaVM *vm = BFUjavaVM;
if (J9_ARE_ANY_BITS_SET(vm->runtimeFlags, J9_RUNTIME_ALLOW_DYNAMIC_AGENT)
&& (0 <= FIND_ARG_IN_VMARGS(EXACT_MATCH, VMOPT_XXENABLEDYNAMICAGENTLOADING, NULL))
) {
result = JNI_FALSE;
}
return result;
}

JNIEXPORT void JNICALL
Expand Down
15 changes: 10 additions & 5 deletions runtime/jvmti/j9jvmti.tdf
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ TraceExit=Trc_JVMTI_issueAgentOnLoadAttach_Exit Overhead=1 Level=1 Noenv Templat
TraceEvent=Trc_JVMTI_issueAgentOnLoadAttach_close_shared_library Overhead=1 Level=1 Noenv Template="issueAgentOnLoadAttach unloading %s"

TraceEntry=Trc_JVMTI_loadAgentLibraryGeneric_Entry Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric loading library %s"
TraceExit=Trc_JVMTI_loadAgentLibraryGeneric_Exit Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric successfully loaded library %s"
TraceExit=Trc_JVMTI_loadAgentLibraryGeneric_Exit Obsolete Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric successfully loaded library %s"

TraceEntry=Trc_JVMTI_loadAgentLibraryOnAttach_Entry Overhead=1 Level=1 Noenv Template="loadAgentLibraryOnAttach loading library %s"
TraceExit=Trc_JVMTI_loadAgentLibraryOnAttach_Exit Overhead=1 Level=1 Noenv Template="loadAgentLibraryOnAttach loaded library %s, status=%d"
Expand Down Expand Up @@ -602,11 +602,11 @@ TraceException=Trc_JVMTI_issueAgentOnLoadAttach_loadFunctionFailed Overhead=1 Le
TraceEvent=Trc_JVMTI_issueAgentOnLoadAttach_loadFunctionSucceeded Overhead=1 Level=5 Noenv Template="issueAgentOnLoadAttach: Load function %s succeeded"

TraceEvent=Trc_JVMTI_loadAgentLibraryGeneric_loadingAgentAs Overhead=1 Level=5 Noenv Template="loadAgentLibraryGeneric: Loading agent as %s"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_execNameNotFound Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: failed obtaining executable name; error code=%d"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_failedOpeningAgentLibrary Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: Failed opening agent library %s"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_execNameNotFound Obsolete Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: failed obtaining executable name; error code=%d"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_failedOpeningAgentLibrary Obsolete Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: Failed opening agent library %s"
TraceEvent=Trc_JVMTI_loadAgentLibraryGeneric_openedAgentLibrary Overhead=1 Level=5 Noenv Template="loadAgentLibraryGeneric: Opened agent %s (address=%p) %s"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed1 Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: Failed attaching agent library; load function %s not found"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed2 Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: Failed attaching agent library; load function failed with error code %zd"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed1 Obsolete Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: Failed attaching agent library; load function %s not found"
TraceException=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed2 Obsolete Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric: Failed attaching agent library; load function failed with error code %zd"
TraceEvent=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachedSuccessfully Overhead=1 Level=5 Noenv Template="loadAgentLibraryGeneric: Attached agent %s successfully"

TraceEvent=Trc_JVMTI_loadAgentLibraryOnAttach_attachingAgentDynamically Overhead=1 Level=5 Noenv Template="loadAgentLibraryOnAttach: Attached agent %s dynamically"
Expand Down Expand Up @@ -660,3 +660,8 @@ TraceEntry=Trc_JVMTI_jvmtiHookVirtualThreadMount_Entry Overhead=1 Level=5 Noenv
TraceExit=Trc_JVMTI_jvmtiHookVirtualThreadMount_Exit Overhead=1 Level=5 Noenv Template="HookVirtualThreadMount"

TraceEvent=Trc_JVMTI_loadAgentLibraryOnAttach_agentLoadingDisabled Overhead=1 Level=5 Noenv Template="loadAgentLibraryOnAttach: Dynamic agent loading is disabled"
TraceExit-Exception=Trc_JVMTI_loadAgentLibraryGeneric_execNameNotFound_Exit Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric failed to obtain executable name with error code=%d while loading library %s"
TraceExit-Exception=Trc_JVMTI_loadAgentLibraryGeneric_failedOpeningAgentLibrary_Exit Overhead==1 Level=1 Noenv Template="loadAgentLibraryGeneric failed to open agent library %s with error message %s"
TraceExit-Exception=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed1_Exit Overhead==1 Level=1 Noenv Template="loadAgentLibraryGeneric failed attaching agent library %s; load function %s not found"
TraceExit-Exception=Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed2_Exit Overhead==1 Level=1 Noenv Template="loadAgentLibraryGeneric failed attaching agent library %s; load function %s failed with error code=%d"
TraceExit=Trc_JVMTI_loadAgentLibraryGeneric_succeed_Exit Overhead=1 Level=1 Noenv Template="loadAgentLibraryGeneric successfully loaded library %s and function %s"
64 changes: 35 additions & 29 deletions runtime/jvmti/jvmtiStartup.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ static jint loadAgentLibrary (J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary)
static jint createXrunLibraries (J9JavaVM * vm);
static J9JVMTIAgentLibrary * findAgentLibrary(J9JavaVM * vm, const char *libraryAndOptions, UDATA libraryLength);
static jint issueAgentOnLoadAttach(J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary, const char* options, char *loadFunctionName, BOOLEAN * foundLoadFn);
I_32 JNICALL loadAgentLibraryOnAttach(struct J9JavaVM * vm, const char * library, const char *options, UDATA decorate) ;

I_32 JNICALL loadAgentLibraryOnAttach(struct J9JavaVM *vm, const char *library, const char *options, UDATA decorate);
static BOOLEAN isAgentLibraryLoaded(J9JavaVM *vm, const char *library);

#define INSTRUMENT_LIBRARY "instrument"

Expand Down Expand Up @@ -212,6 +212,7 @@ IDATA J9VMDllMain(J9JavaVM* vm, IDATA stage, void* reserved)
}

vm->loadAgentLibraryOnAttach = &loadAgentLibraryOnAttach;
vm->isAgentLibraryLoaded = &isAgentLibraryLoaded;

break;
}
Expand Down Expand Up @@ -446,45 +447,50 @@ issueAgentOnLoadAttach(J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary, const
}

/**
* Load a JVMTI agent and call the agent's initialization function
* @param vm Java VM
* @param agentLibrary environment for the agent
* @param name of the initialization function
* @return JNI_ERR, JNI_OK
* Load a JVMTI agent and call the agent's initialization function.
*
* @param[in] vm Java VM
* @param[in] agentLibrary environment for the agent
* @param[in] loadFunctionName name of the initialization function
* @param[in] loadStatically a boolean indicating if the library is to be loaded statically
* @param[in/out] found a pointer to a boolean indicating whether the load function was found
* @param[in/out] errorMessage a pointer to the error message when opening the shared library
*
* @return JNI_ERR if failed, otherwise JNI_OK
*/
static jint
loadAgentLibraryGeneric(J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary, char *loadFunctionName, BOOLEAN loadStatically, BOOLEAN * found, const char **errorMessage)
loadAgentLibraryGeneric(J9JavaVM *vm, J9JVMTIAgentLibrary *agentLibrary, char *loadFunctionName, BOOLEAN loadStatically, BOOLEAN *found, const char **errorMessage)
{
PORT_ACCESS_FROM_JAVAVM(vm);
jint rc;
J9JVMTIData * jvmtiData = J9JVMTI_DATA_FROM_VM(vm);
J9NativeLibrary * nativeLib = &(agentLibrary->nativeLib);
jint rc = JNI_OK;
J9JVMTIData *jvmtiData = J9JVMTI_DATA_FROM_VM(vm);
J9NativeLibrary *nativeLib = &(agentLibrary->nativeLib);

Trc_JVMTI_loadAgentLibraryGeneric_Entry(agentLibrary->nativeLib.name);
if (NULL == agentLibrary->xRunLibrary) {
jint i = 0;
char * fullLibName = NULL;
const char * systemAgentName;
char *fullLibName = NULL;
const char *systemAgentName = NULL;
UDATA openFlags = agentLibrary->decorate ? J9PORT_SLOPEN_DECORATE | J9PORT_SLOPEN_LAZY : J9PORT_SLOPEN_LAZY;
char * agentPath = NULL; /* Don't free agentPath; may point at persistent, system areas. */
char *agentPath = NULL; /* Don't free agentPath; may point at persistent, system areas. */

if (loadStatically) {
/* If flag is set, the agent library ought to be opened statically, that is, the executable itself. */
if (0 == j9sysinfo_get_executable_name(NULL, &agentPath)) {
openFlags |= J9PORT_SLOPEN_OPEN_EXECUTABLE;
} else {
/* Report failure to obtain executable name; caller will proceed with dynamic linking. */
Trc_JVMTI_loadAgentLibraryGeneric_execNameNotFound(j9error_last_error_number());
Trc_JVMTI_loadAgentLibraryGeneric_Exit(agentLibrary->nativeLib.name);
I_32 errorno = j9error_last_error_number();
Trc_JVMTI_loadAgentLibraryGeneric_execNameNotFound_Exit(errorno, agentLibrary->nativeLib.name);
return JNI_ERR;
}
} else {
/* If the user did not specify an explicit agent path, then ensure that the library
* is loaded from our current jre tree. This avoids picking up stray agents that might
* be found on the library path. See CMVC 144382.
*/
while ((systemAgentName = systemAgentNames[i++]) != NULL) {
if (strcmp(nativeLib->name, systemAgentName) == 0) {
while (NULL != (systemAgentName = systemAgentNames[i++])) {
if (0 == strcmp(nativeLib->name, systemAgentName)) {
fullLibName = prependSystemAgentPath(vm, agentLibrary, nativeLib->name);
Trc_JVMTI_loadAgentLibraryGeneric_loadingAgentAs(fullLibName);
break;
Expand All @@ -493,17 +499,15 @@ loadAgentLibraryGeneric(J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary, char
agentPath = (NULL != fullLibName) ? fullLibName : nativeLib->name;
}

if (j9sl_open_shared_library(agentPath, &(nativeLib->handle), openFlags) != 0) {
Trc_JVMTI_loadAgentLibraryGeneric_failedOpeningAgentLibrary(agentPath);

if (0 != j9sl_open_shared_library(agentPath, &(nativeLib->handle), openFlags)) {
/* We may attempt to open the shared library again so save the error message
* and print it once we know it is the final attempt */
*errorMessage = j9error_last_error_message();

if (NULL != fullLibName) {
j9mem_free_memory(fullLibName);
}
Trc_JVMTI_loadAgentLibraryGeneric_Exit(agentPath);
Trc_JVMTI_loadAgentLibraryGeneric_failedOpeningAgentLibrary_Exit(agentPath, *errorMessage);
return JNI_ERR;
}
Trc_JVMTI_loadAgentLibraryGeneric_openedAgentLibrary(agentPath,
Expand All @@ -519,15 +523,13 @@ loadAgentLibraryGeneric(J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary, char
rc = issueAgentOnLoadAttach(vm, agentLibrary, agentLibrary->options, loadFunctionName, found);
if (!(*found)) {
/* If the load function wasn't found, issueAgentOnLoadAttach already closed the library. */
Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed1(loadFunctionName);
Trc_JVMTI_loadAgentLibraryGeneric_Exit(agentLibrary->nativeLib.name);
Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed1_Exit(agentLibrary->nativeLib.name, loadFunctionName);
return rc;
}

/* For errors other than load function not found ... */
if (JNI_OK != rc) {
Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed2(rc);
Trc_JVMTI_loadAgentLibraryGeneric_Exit(agentLibrary->nativeLib.name);
Trc_JVMTI_loadAgentLibraryGeneric_agentAttachFailed2_Exit(agentLibrary->nativeLib.name, loadFunctionName, rc);
return rc;
}

Expand All @@ -540,14 +542,14 @@ loadAgentLibraryGeneric(J9JavaVM * vm, J9JVMTIAgentLibrary * agentLibrary, char
/* Add the library to the linked list */
issueWriteBarrier();
omrthread_monitor_enter(jvmtiData->mutex);
if (jvmtiData->agentLibrariesTail == NULL) {
if (NULL == jvmtiData->agentLibrariesTail) {
jvmtiData->agentLibrariesHead = jvmtiData->agentLibrariesTail = nativeLib;
} else {
jvmtiData->agentLibrariesTail->next = nativeLib;
jvmtiData->agentLibrariesTail = nativeLib;
}
omrthread_monitor_exit(jvmtiData->mutex);
Trc_JVMTI_loadAgentLibraryGeneric_Exit(agentLibrary->nativeLib.name);
Trc_JVMTI_loadAgentLibraryGeneric_succeed_Exit(agentLibrary->nativeLib.name, loadFunctionName);

return JNI_OK;
}
Expand Down Expand Up @@ -1060,6 +1062,11 @@ createXrunLibraries(J9JavaVM * vm)
return JNI_OK;
}

static BOOLEAN
isAgentLibraryLoaded(J9JavaVM *vm, const char *library)
{
return NULL != findAgentLibrary(vm, library, strlen(library));
}

static J9JVMTIAgentLibrary *
findAgentLibrary(J9JavaVM * vm, const char *libraryAndOptions, UDATA libraryLength)
Expand Down Expand Up @@ -1087,4 +1094,3 @@ findAgentLibrary(J9JavaVM * vm, const char *libraryAndOptions, UDATA libraryLeng

return NULL;
}

1 change: 1 addition & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5802,6 +5802,7 @@ typedef struct J9JavaVM {
omrthread_monitor_t statisticsMutex;
struct J9Statistic* nextStatistic;
I_32 (JNICALL *loadAgentLibraryOnAttach)(struct J9JavaVM * vm, const char * library, const char *options, UDATA decorate) ;
BOOLEAN (*isAgentLibraryLoaded)(struct J9JavaVM *vm, const char *library);
struct J9AttachContext attachContext;
UDATA hotSwapCount;
UDATA zombieThreadCount;
Expand Down
39 changes: 28 additions & 11 deletions runtime/vm/BytecodeInterpreter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,27 @@
#include <errno.h>
#endif /* JAVA_SPEC_VERSION >= 20 */

#include "bcnames.h"
#define FFI_BUILDING /* Needed on Windows to link libffi statically */
#include "ffi.h"
#include "j2sever.h"
#include "j9.h"
#include "j9bcvnls.h"
#include "j9cfg.h"
#include "j9protos.h"
#include "j9consts.h"
#include "j9vmnls.h"
#include "j9jclnls.h"
#include "j9bcvnls.h"
#include "bcnames.h"
#include "j9protos.h"
#include "j9vmnls.h"
#include "jitregmap.h"
#include "jni.h"
#include "jvminit.h"
#include "objhelp.h"
#include "rommeth.h"
#include "stackwalk.h"
#include "ut_j9vm.h"
#include "util_api.h"
#include "vm_internal.h"
#include "jni.h"
#define FFI_BUILDING /* Needed on Windows to link libffi statically */
#include "ffi.h"
#include "jitregmap.h"
#include "j2sever.h"
#include "vmaccess.h"
#include "objhelp.h"

#include "ArrayCopyHelpers.hpp"
#include "AtomicSupport.hpp"
Expand Down Expand Up @@ -4863,8 +4864,24 @@ class INTERPRETER_CLASS
// Trc_JCL_attach_loadAgentLibrary(env, agentLibraryUTF, agentOptions, decorate);
const char *agentOptionsUTF = env->GetStringUTFChars(agentOptions, NULL);
if (NULL != agentOptionsUTF) {
if (J9_ARE_ANY_BITS_SET(_vm->runtimeFlags, J9_RUNTIME_ALLOW_DYNAMIC_AGENT)) {
#if JAVA_SPEC_VERSION >= 21
/* The name "vm" is used by FIND_ARG_IN_VMARGS(). */
J9JavaVM *vm = _vm;
/* No warning if -XX:+EnableDynamicAgentLoading is specified. */
if (0 > FIND_ARG_IN_VMARGS(EXACT_MATCH, VMOPT_XXENABLEDYNAMICAGENTLOADING, NULL)) {
/* No warning if the same agent is already loaded. */
if (!vm->isAgentLibraryLoaded(vm, agentLibraryUTF)) {
fprintf(stderr, "WARNING: A JVM TI agent has been loaded dynamically (%s)\n", agentOptionsUTF);
fprintf(stderr, "WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning\n");
fprintf(stderr, "WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information\n");
fprintf(stderr, "WARNING: Dynamic loading of agents will be disallowed by default in a future release\n");
}
}
#endif /* JAVA_SPEC_VERSION >= 21 */
status = (_vm->loadAgentLibraryOnAttach)(_vm, agentLibraryUTF, agentOptionsUTF, decorate);
env->ReleaseStringUTFChars(agentOptions, agentOptionsUTF);
}
env->ReleaseStringUTFChars(agentOptions, agentOptionsUTF);
}
env->ReleaseStringUTFChars(agentLibrary, agentLibraryUTF);
}
Expand Down

0 comments on commit 58047f8

Please sign in to comment.