Blame SOURCES/jdk8258836-jni_local_refs_exceed_capacity.patch

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
+}