|
|
59c681 |
# HG changeset patch
|
|
|
59c681 |
# User sgehwolf
|
|
|
59c681 |
# Date 1611565076 0
|
|
|
59c681 |
# Mon Jan 25 08:57:56 2021 +0000
|
|
|
59c681 |
# Node ID 61c497b3b886f671646aec9d6e4cf3f44c422f99
|
|
|
59c681 |
# Parent 59a62286b0b2a3057040df83640f38ea9499a60c
|
|
|
59c681 |
8258836: JNI local refs exceed capacity getDiagnosticCommandInfo
|
|
|
59c681 |
Reviewed-by: cjplummer, shade
|
|
|
59c681 |
|
|
|
59c681 |
diff --git a/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c b/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c
|
|
|
59c681 |
--- a/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c
|
|
|
59c681 |
+++ b/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c
|
|
|
59c681 |
@@ -1,5 +1,5 @@
|
|
|
59c681 |
/*
|
|
|
59c681 |
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
|
59c681 |
+ * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
|
|
59c681 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
59c681 |
*
|
|
|
59c681 |
* This code is free software; you can redistribute it and/or modify it
|
|
|
59c681 |
@@ -45,12 +45,21 @@
|
|
|
59c681 |
return jmm_interface->GetDiagnosticCommands(env);
|
|
|
59c681 |
}
|
|
|
59c681 |
|
|
|
59c681 |
-#define EXCEPTION_CHECK_AND_FREE(x) do { \
|
|
|
59c681 |
- if ((*env)->ExceptionCheck(env)) { \
|
|
|
59c681 |
- free(x); \
|
|
|
59c681 |
- return NULL; \
|
|
|
59c681 |
- } \
|
|
|
59c681 |
- } while(0)
|
|
|
59c681 |
+//
|
|
|
59c681 |
+// Checks for an exception and if one occurred,
|
|
|
59c681 |
+// pops 'pops' local frames and frees 'x' before
|
|
|
59c681 |
+// returning NULL
|
|
|
59c681 |
+//
|
|
|
59c681 |
+#define POP_EXCEPTION_CHECK_AND_FREE(pops, x) do { \
|
|
|
59c681 |
+ if ((*env)->ExceptionCheck(env)) { \
|
|
|
59c681 |
+ int i; \
|
|
|
59c681 |
+ for (i = 0; i < pops; i++) { \
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL); \
|
|
|
59c681 |
+ } \
|
|
|
59c681 |
+ free(x); \
|
|
|
59c681 |
+ return NULL; \
|
|
|
59c681 |
+ } \
|
|
|
59c681 |
+ } while(0)
|
|
|
59c681 |
|
|
|
59c681 |
jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
|
|
|
59c681 |
int num_arg) {
|
|
|
59c681 |
@@ -73,10 +82,7 @@
|
|
|
59c681 |
dcmd_arg_info_array);
|
|
|
59c681 |
dcmdArgInfoCls = (*env)->FindClass(env,
|
|
|
59c681 |
"com/sun/management/internal/DiagnosticCommandArgumentInfo");
|
|
|
59c681 |
- if ((*env)->ExceptionCheck(env)) {
|
|
|
59c681 |
- free(dcmd_arg_info_array);
|
|
|
59c681 |
- return NULL;
|
|
|
59c681 |
- }
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(0, dcmd_arg_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
result = (*env)->NewObjectArray(env, num_arg, dcmdArgInfoCls, NULL);
|
|
|
59c681 |
if (result == NULL) {
|
|
|
59c681 |
@@ -84,19 +90,21 @@
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
for (i=0; i
|
|
|
59c681 |
- jstring jname, jdesc,jtype,jdefStr;
|
|
|
59c681 |
+ // Capacity for 5 local refs: jname, jdesc, jtype, jdefStr and obj
|
|
|
59c681 |
+ (*env)->PushLocalFrame(env, 5);
|
|
|
59c681 |
+ jstring jname, jdesc, jtype, jdefStr;
|
|
|
59c681 |
|
|
|
59c681 |
jname = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].name);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
jdesc = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].description);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
jtype = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].type);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
jdefStr = (*env)->NewStringUTF(env, dcmd_arg_info_array[i].default_string);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
|
|
|
59c681 |
obj = JNU_NewObjectByName(env,
|
|
|
59c681 |
"com/sun/management/internal/DiagnosticCommandArgumentInfo",
|
|
|
59c681 |
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZI)V",
|
|
|
59c681 |
@@ -107,11 +115,13 @@
|
|
|
59c681 |
dcmd_arg_info_array[i].multiple,
|
|
|
59c681 |
dcmd_arg_info_array[i].position);
|
|
|
59c681 |
if (obj == NULL) {
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
free(dcmd_arg_info_array);
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
+ obj = (*env)->PopLocalFrame(env, obj);
|
|
|
59c681 |
(*env)->SetObjectArrayElement(env, result, i, obj);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(0, dcmd_arg_info_array);
|
|
|
59c681 |
}
|
|
|
59c681 |
free(dcmd_arg_info_array);
|
|
|
59c681 |
arraysCls = (*env)->FindClass(env, "java/util/Arrays");
|
|
|
59c681 |
@@ -144,51 +154,67 @@
|
|
|
59c681 |
jint ret = jmm_interface->GetOptionalSupport(env, &mos;;
|
|
|
59c681 |
jsize num_commands;
|
|
|
59c681 |
dcmdInfo* dcmd_info_array;
|
|
|
59c681 |
- jstring jname, jdesc, jimpact;
|
|
|
59c681 |
+ jstring jname, jdesc, jimpact, cmd;
|
|
|
59c681 |
|
|
|
59c681 |
if (commands == NULL) {
|
|
|
59c681 |
JNU_ThrowNullPointerException(env, "Invalid String Array");
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
num_commands = (*env)->GetArrayLength(env, commands);
|
|
|
59c681 |
+ // Ensure capacity for 2 + num_commands local refs:
|
|
|
59c681 |
+ // 2 => dcmdInfoCls, result
|
|
|
59c681 |
+ // num_commmands => one obj per command
|
|
|
59c681 |
+ (*env)->PushLocalFrame(env, 2 + num_commands);
|
|
|
59c681 |
dcmdInfoCls = (*env)->FindClass(env,
|
|
|
59c681 |
"com/sun/management/internal/DiagnosticCommandInfo");
|
|
|
59c681 |
if ((*env)->ExceptionCheck(env)) {
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
|
|
|
59c681 |
result = (*env)->NewObjectArray(env, num_commands, dcmdInfoCls, NULL);
|
|
|
59c681 |
if (result == NULL) {
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
if (num_commands == 0) {
|
|
|
59c681 |
+ result = (*env)->PopLocalFrame(env, result);
|
|
|
59c681 |
/* Handle the 'zero commands' case specially to avoid calling 'malloc()' */
|
|
|
59c681 |
/* with a zero argument because that may legally return a NULL pointer. */
|
|
|
59c681 |
return result;
|
|
|
59c681 |
}
|
|
|
59c681 |
dcmd_info_array = (dcmdInfo*) malloc(num_commands * sizeof(dcmdInfo));
|
|
|
59c681 |
if (dcmd_info_array == NULL) {
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
JNU_ThrowOutOfMemoryError(env, NULL);
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
jmm_interface->GetDiagnosticCommandInfo(env, commands, dcmd_info_array);
|
|
|
59c681 |
for (i=0; i
|
|
|
59c681 |
+ // Ensure capacity for 6 + 3 local refs:
|
|
|
59c681 |
+ // 6 => jname, jdesc, jimpact, cmd, args, obj
|
|
|
59c681 |
+ // 3 => permission class, name, action
|
|
|
59c681 |
+ (*env)->PushLocalFrame(env, 6 + 3);
|
|
|
59c681 |
+
|
|
|
59c681 |
+ cmd = (*env)->GetObjectArrayElement(env, commands, i);
|
|
|
59c681 |
args = getDiagnosticCommandArgumentInfoArray(env,
|
|
|
59c681 |
- (*env)->GetObjectArrayElement(env,commands,i),
|
|
|
59c681 |
+ cmd,
|
|
|
59c681 |
dcmd_info_array[i].num_arguments);
|
|
|
59c681 |
if (args == NULL) {
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
free(dcmd_info_array);
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
|
|
|
59c681 |
jname = (*env)->NewStringUTF(env,dcmd_info_array[i].name);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(2, dcmd_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
jdesc = (*env)->NewStringUTF(env,dcmd_info_array[i].description);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(2, dcmd_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
jimpact = (*env)->NewStringUTF(env,dcmd_info_array[i].impact);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(2, dcmd_info_array);
|
|
|
59c681 |
|
|
|
59c681 |
obj = JNU_NewObjectByName(env,
|
|
|
59c681 |
"com/sun/management/internal/DiagnosticCommandInfo",
|
|
|
59c681 |
@@ -200,13 +226,17 @@
|
|
|
59c681 |
dcmd_info_array[i].enabled,
|
|
|
59c681 |
args);
|
|
|
59c681 |
if (obj == NULL) {
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
+ (*env)->PopLocalFrame(env, NULL);
|
|
|
59c681 |
free(dcmd_info_array);
|
|
|
59c681 |
return NULL;
|
|
|
59c681 |
}
|
|
|
59c681 |
+ obj = (*env)->PopLocalFrame(env, obj);
|
|
|
59c681 |
|
|
|
59c681 |
(*env)->SetObjectArrayElement(env, result, i, obj);
|
|
|
59c681 |
- EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
|
|
|
59c681 |
+ POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_info_array);
|
|
|
59c681 |
}
|
|
|
59c681 |
+ result = (*env)->PopLocalFrame(env, result);
|
|
|
59c681 |
free(dcmd_info_array);
|
|
|
59c681 |
return result;
|
|
|
59c681 |
}
|
|
|
59c681 |
diff --git a/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTestCheckJni.java b/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTestCheckJni.java
|
|
|
59c681 |
new file mode 100644
|
|
|
59c681 |
--- /dev/null
|
|
|
59c681 |
+++ b/test/jdk/com/sun/management/DiagnosticCommandMBean/DcmdMBeanTestCheckJni.java
|
|
|
59c681 |
@@ -0,0 +1,84 @@
|
|
|
59c681 |
+/*
|
|
|
59c681 |
+ * Copyright (c) 2021, Red Hat, Inc.
|
|
|
59c681 |
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
59c681 |
+ *
|
|
|
59c681 |
+ * This code is free software; you can redistribute it and/or modify it
|
|
|
59c681 |
+ * under the terms of the GNU General Public License version 2 only, as
|
|
|
59c681 |
+ * published by the Free Software Foundation.
|
|
|
59c681 |
+ *
|
|
|
59c681 |
+ * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
59c681 |
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
59c681 |
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
59c681 |
+ * version 2 for more details (a copy is included in the LICENSE file that
|
|
|
59c681 |
+ * accompanied this code).
|
|
|
59c681 |
+ *
|
|
|
59c681 |
+ * You should have received a copy of the GNU General Public License version
|
|
|
59c681 |
+ * 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
59c681 |
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
59c681 |
+ *
|
|
|
59c681 |
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
59c681 |
+ * or visit www.oracle.com if you need additional information or have any
|
|
|
59c681 |
+ * questions.
|
|
|
59c681 |
+ */
|
|
|
59c681 |
+
|
|
|
59c681 |
+/*
|
|
|
59c681 |
+ * @test
|
|
|
59c681 |
+ * @bug 8258836
|
|
|
59c681 |
+ * @summary JNI local refs exceed capacity getDiagnosticCommandInfo
|
|
|
59c681 |
+ * @library /test/lib
|
|
|
59c681 |
+ * @run main/othervm DcmdMBeanTestCheckJni
|
|
|
59c681 |
+ */
|
|
|
59c681 |
+
|
|
|
59c681 |
+import java.lang.management.ManagementFactory;
|
|
|
59c681 |
+import javax.management.MBeanServer;
|
|
|
59c681 |
+import javax.management.ObjectName;
|
|
|
59c681 |
+import javax.management.MBeanServerConnection;
|
|
|
59c681 |
+import javax.management.remote.JMXConnectorFactory;
|
|
|
59c681 |
+import javax.management.remote.JMXConnector;
|
|
|
59c681 |
+import javax.management.remote.JMXConnectorServerFactory;
|
|
|
59c681 |
+import javax.management.remote.JMXServiceURL;
|
|
|
59c681 |
+import javax.management.remote.JMXConnectorServer;
|
|
|
59c681 |
+
|
|
|
59c681 |
+import jdk.test.lib.process.OutputAnalyzer;
|
|
|
59c681 |
+import jdk.test.lib.process.ProcessTools;
|
|
|
59c681 |
+
|
|
|
59c681 |
+public class DcmdMBeanTestCheckJni {
|
|
|
59c681 |
+
|
|
|
59c681 |
+ public static void main(String[] args) throws Exception {
|
|
|
59c681 |
+ OutputAnalyzer out = ProcessTools.executeTestJvm(
|
|
|
59c681 |
+ "-Xcheck:jni",
|
|
|
59c681 |
+ DcmdMBeanRunner.class.getName());
|
|
|
59c681 |
+ out.shouldNotMatch("WARNING: JNI local refs: \\d+, exceeds capacity: \\d+")
|
|
|
59c681 |
+ .shouldContain("DcmdMBeanRunner COMPLETE")
|
|
|
59c681 |
+ .shouldHaveExitValue(0);
|
|
|
59c681 |
+ }
|
|
|
59c681 |
+
|
|
|
59c681 |
+}
|
|
|
59c681 |
+
|
|
|
59c681 |
+class DcmdMBeanRunner {
|
|
|
59c681 |
+
|
|
|
59c681 |
+ private static final String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
|
|
|
59c681 |
+ "com.sun.management:type=DiagnosticCommand";
|
|
|
59c681 |
+
|
|
|
59c681 |
+ public static void main(String[] args) throws Exception {
|
|
|
59c681 |
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
|
|
59c681 |
+ JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
|
|
|
59c681 |
+ JMXConnectorServer cs = null;
|
|
|
59c681 |
+ JMXConnector cc = null;
|
|
|
59c681 |
+ try {
|
|
|
59c681 |
+ cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
|
|
|
59c681 |
+ cs.start();
|
|
|
59c681 |
+ JMXServiceURL addr = cs.getAddress();
|
|
|
59c681 |
+ cc = JMXConnectorFactory.connect(addr);
|
|
|
59c681 |
+ MBeanServerConnection mbsc = cc.getMBeanServerConnection();
|
|
|
59c681 |
+ ObjectName name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME);
|
|
|
59c681 |
+ System.out.println("DiagnosticCommand MBean: " + name);
|
|
|
59c681 |
+ System.out.println("DcmdMBeanRunner COMPLETE");
|
|
|
59c681 |
+ } finally {
|
|
|
59c681 |
+ try {
|
|
|
59c681 |
+ cc.close();
|
|
|
59c681 |
+ cs.stop();
|
|
|
59c681 |
+ } catch (Exception e) { /* ignored */ }
|
|
|
59c681 |
+ }
|
|
|
59c681 |
+ }
|
|
|
59c681 |
+}
|