Skip to content
This repository was archived by the owner on Aug 27, 2022. It is now read-only.
/ lanai Public archive

Commit af155fc

Browse files
committedJan 25, 2021
8258836: JNI local refs exceed capacity getDiagnosticCommandInfo
Reviewed-by: cjplummer, shade
1 parent d825339 commit af155fc

File tree

2 files changed

+137
-23
lines changed

2 files changed

+137
-23
lines changed
 

‎src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c

+53-23
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -45,12 +45,21 @@ Java_com_sun_management_internal_DiagnosticCommandImpl_getDiagnosticCommands
4545
return jmm_interface->GetDiagnosticCommands(env);
4646
}
4747

48-
#define EXCEPTION_CHECK_AND_FREE(x) do { \
49-
if ((*env)->ExceptionCheck(env)) { \
50-
free(x); \
51-
return NULL; \
52-
} \
53-
} while(0)
48+
//
49+
// Checks for an exception and if one occurred,
50+
// pops 'pops' local frames and frees 'x' before
51+
// returning NULL
52+
//
53+
#define POP_EXCEPTION_CHECK_AND_FREE(pops, x) do { \
54+
if ((*env)->ExceptionCheck(env)) { \
55+
int i; \
56+
for (i = 0; i < pops; i++) { \
57+
(*env)->PopLocalFrame(env, NULL); \
58+
} \
59+
free(x); \
60+
return NULL; \
61+
} \
62+
} while(0)
5463

5564
jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
5665
int num_arg) {
@@ -73,30 +82,29 @@ jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
7382
dcmd_arg_info_array);
7483
dcmdArgInfoCls = (*env)->FindClass(env,
7584
"com/sun/management/internal/DiagnosticCommandArgumentInfo");
76-
if ((*env)->ExceptionCheck(env)) {
77-
free(dcmd_arg_info_array);
78-
return NULL;
79-
}
85+
POP_EXCEPTION_CHECK_AND_FREE(0, dcmd_arg_info_array);
8086

8187
result = (*env)->NewObjectArray(env, num_arg, dcmdArgInfoCls, NULL);
8288
if (result == NULL) {
8389
free(dcmd_arg_info_array);
8490
return NULL;
8591
}
8692
for (i=0; i<num_arg; i++) {
87-
jstring jname, jdesc,jtype,jdefStr;
93+
// Capacity for 5 local refs: jname, jdesc, jtype, jdefStr and obj
94+
(*env)->PushLocalFrame(env, 5);
95+
jstring jname, jdesc, jtype, jdefStr;
8896

8997
jname = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].name);
90-
EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
98+
POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
9199

92100
jdesc = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].description);
93-
EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
101+
POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
94102

95103
jtype = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].type);
96-
EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
104+
POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
97105

98106
jdefStr = (*env)->NewStringUTF(env, dcmd_arg_info_array[i].default_string);
99-
EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
107+
POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_arg_info_array);
100108
obj = JNU_NewObjectByName(env,
101109
"com/sun/management/internal/DiagnosticCommandArgumentInfo",
102110
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZI)V",
@@ -107,11 +115,13 @@ jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
107115
dcmd_arg_info_array[i].multiple,
108116
dcmd_arg_info_array[i].position);
109117
if (obj == NULL) {
118+
(*env)->PopLocalFrame(env, NULL);
110119
free(dcmd_arg_info_array);
111120
return NULL;
112121
}
122+
obj = (*env)->PopLocalFrame(env, obj);
113123
(*env)->SetObjectArrayElement(env, result, i, obj);
114-
EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
124+
POP_EXCEPTION_CHECK_AND_FREE(0, dcmd_arg_info_array);
115125
}
116126
free(dcmd_arg_info_array);
117127
arraysCls = (*env)->FindClass(env, "java/util/Arrays");
@@ -144,51 +154,67 @@ Java_com_sun_management_internal_DiagnosticCommandImpl_getDiagnosticCommandInfo
144154
jint ret = jmm_interface->GetOptionalSupport(env, &mos);
145155
jsize num_commands;
146156
dcmdInfo* dcmd_info_array;
147-
jstring jname, jdesc, jimpact;
157+
jstring jname, jdesc, jimpact, cmd;
148158

149159
if (commands == NULL) {
150160
JNU_ThrowNullPointerException(env, "Invalid String Array");
151161
return NULL;
152162
}
153163
num_commands = (*env)->GetArrayLength(env, commands);
164+
// Ensure capacity for 2 + num_commands local refs:
165+
// 2 => dcmdInfoCls, result
166+
// num_commmands => one obj per command
167+
(*env)->PushLocalFrame(env, 2 + num_commands);
154168
dcmdInfoCls = (*env)->FindClass(env,
155169
"com/sun/management/internal/DiagnosticCommandInfo");
156170
if ((*env)->ExceptionCheck(env)) {
171+
(*env)->PopLocalFrame(env, NULL);
157172
return NULL;
158173
}
159174

160175
result = (*env)->NewObjectArray(env, num_commands, dcmdInfoCls, NULL);
161176
if (result == NULL) {
177+
(*env)->PopLocalFrame(env, NULL);
162178
return NULL;
163179
}
164180
if (num_commands == 0) {
181+
result = (*env)->PopLocalFrame(env, result);
165182
/* Handle the 'zero commands' case specially to avoid calling 'malloc()' */
166183
/* with a zero argument because that may legally return a NULL pointer. */
167184
return result;
168185
}
169186
dcmd_info_array = (dcmdInfo*) malloc(num_commands * sizeof(dcmdInfo));
170187
if (dcmd_info_array == NULL) {
188+
(*env)->PopLocalFrame(env, NULL);
171189
JNU_ThrowOutOfMemoryError(env, NULL);
172190
return NULL;
173191
}
174192
jmm_interface->GetDiagnosticCommandInfo(env, commands, dcmd_info_array);
175193
for (i=0; i<num_commands; i++) {
194+
// Ensure capacity for 6 + 3 local refs:
195+
// 6 => jname, jdesc, jimpact, cmd, args, obj
196+
// 3 => permission class, name, action
197+
(*env)->PushLocalFrame(env, 6 + 3);
198+
199+
cmd = (*env)->GetObjectArrayElement(env, commands, i);
176200
args = getDiagnosticCommandArgumentInfoArray(env,
177-
(*env)->GetObjectArrayElement(env,commands,i),
201+
cmd,
178202
dcmd_info_array[i].num_arguments);
179203
if (args == NULL) {
204+
(*env)->PopLocalFrame(env, NULL);
205+
(*env)->PopLocalFrame(env, NULL);
180206
free(dcmd_info_array);
181207
return NULL;
182208
}
183209

184210
jname = (*env)->NewStringUTF(env,dcmd_info_array[i].name);
185-
EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
211+
POP_EXCEPTION_CHECK_AND_FREE(2, dcmd_info_array);
186212

187213
jdesc = (*env)->NewStringUTF(env,dcmd_info_array[i].description);
188-
EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
214+
POP_EXCEPTION_CHECK_AND_FREE(2, dcmd_info_array);
189215

190216
jimpact = (*env)->NewStringUTF(env,dcmd_info_array[i].impact);
191-
EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
217+
POP_EXCEPTION_CHECK_AND_FREE(2, dcmd_info_array);
192218

193219
obj = JNU_NewObjectByName(env,
194220
"com/sun/management/internal/DiagnosticCommandInfo",
@@ -200,13 +226,17 @@ Java_com_sun_management_internal_DiagnosticCommandImpl_getDiagnosticCommandInfo
200226
dcmd_info_array[i].enabled,
201227
args);
202228
if (obj == NULL) {
229+
(*env)->PopLocalFrame(env, NULL);
230+
(*env)->PopLocalFrame(env, NULL);
203231
free(dcmd_info_array);
204232
return NULL;
205233
}
234+
obj = (*env)->PopLocalFrame(env, obj);
206235

207236
(*env)->SetObjectArrayElement(env, result, i, obj);
208-
EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
237+
POP_EXCEPTION_CHECK_AND_FREE(1, dcmd_info_array);
209238
}
239+
result = (*env)->PopLocalFrame(env, result);
210240
free(dcmd_info_array);
211241
return result;
212242
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2021, Red Hat, Inc.
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+
/*
25+
* @test
26+
* @bug 8258836
27+
* @summary JNI local refs exceed capacity getDiagnosticCommandInfo
28+
* @library /test/lib
29+
* @run main/othervm DcmdMBeanTestCheckJni
30+
*/
31+
32+
import java.lang.management.ManagementFactory;
33+
import javax.management.MBeanServer;
34+
import javax.management.ObjectName;
35+
import javax.management.MBeanServerConnection;
36+
import javax.management.remote.JMXConnectorFactory;
37+
import javax.management.remote.JMXConnector;
38+
import javax.management.remote.JMXConnectorServerFactory;
39+
import javax.management.remote.JMXServiceURL;
40+
import javax.management.remote.JMXConnectorServer;
41+
42+
import jdk.test.lib.process.OutputAnalyzer;
43+
import jdk.test.lib.process.ProcessTools;
44+
45+
public class DcmdMBeanTestCheckJni {
46+
47+
public static void main(String[] args) throws Exception {
48+
OutputAnalyzer out = ProcessTools.executeTestJvm(
49+
"-Xcheck:jni",
50+
DcmdMBeanRunner.class.getName());
51+
out.shouldNotMatch("WARNING: JNI local refs: \\d+, exceeds capacity: \\d+")
52+
.shouldContain("DcmdMBeanRunner COMPLETE")
53+
.shouldHaveExitValue(0);
54+
}
55+
56+
}
57+
58+
class DcmdMBeanRunner {
59+
60+
private static final String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
61+
"com.sun.management:type=DiagnosticCommand";
62+
63+
public static void main(String[] args) throws Exception {
64+
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
65+
JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
66+
JMXConnectorServer cs = null;
67+
JMXConnector cc = null;
68+
try {
69+
cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
70+
cs.start();
71+
JMXServiceURL addr = cs.getAddress();
72+
cc = JMXConnectorFactory.connect(addr);
73+
MBeanServerConnection mbsc = cc.getMBeanServerConnection();
74+
ObjectName name = new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME);
75+
System.out.println("DiagnosticCommand MBean: " + name);
76+
System.out.println("DcmdMBeanRunner COMPLETE");
77+
} finally {
78+
try {
79+
cc.close();
80+
cs.stop();
81+
} catch (Exception e) { /* ignored */ }
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)
This repository has been archived.