comparison src/share/instrument/JPLISAgent.c @ 4882:3c1ab134db71

7121600: Instrumentation.redefineClasses() leaks class bytes Summary: Call JNI ReleaseByteArrayElements() on memory returned by JNI GetByteArrayElements(). Also push test for 7122253. Reviewed-by: acorn, poonam
author dcubed
date Thu, 22 Dec 2011 18:35:48 -0800
parents 272483f6650b
children
comparison
equal deleted inserted replaced
9:ecc685f59086 10:02afd0eb2db9
1162 jboolean errorOccurred = JNI_FALSE; 1162 jboolean errorOccurred = JNI_FALSE;
1163 jclass classDefClass = NULL; 1163 jclass classDefClass = NULL;
1164 jmethodID getDefinitionClassMethodID = NULL; 1164 jmethodID getDefinitionClassMethodID = NULL;
1165 jmethodID getDefinitionClassFileMethodID = NULL; 1165 jmethodID getDefinitionClassFileMethodID = NULL;
1166 jvmtiClassDefinition* classDefs = NULL; 1166 jvmtiClassDefinition* classDefs = NULL;
1167 jbyteArray* targetFiles = NULL;
1167 jsize numDefs = 0; 1168 jsize numDefs = 0;
1168 1169
1169 jplis_assert(classDefinitions != NULL); 1170 jplis_assert(classDefinitions != NULL);
1170 1171
1171 numDefs = (*jnienv)->GetArrayLength(jnienv, classDefinitions); 1172 numDefs = (*jnienv)->GetArrayLength(jnienv, classDefinitions);
1205 errorOccurred = (classDefs == NULL); 1206 errorOccurred = (classDefs == NULL);
1206 jplis_assert(!errorOccurred); 1207 jplis_assert(!errorOccurred);
1207 if ( errorOccurred ) { 1208 if ( errorOccurred ) {
1208 createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY); 1209 createAndThrowThrowableFromJVMTIErrorCode(jnienv, JVMTI_ERROR_OUT_OF_MEMORY);
1209 } 1210 }
1211
1210 else { 1212 else {
1211 jint i; 1213 /*
1212 for (i = 0; i < numDefs; i++) { 1214 * We have to save the targetFile values that we compute so
1213 jclass classDef = NULL; 1215 * that we can release the class_bytes arrays that are
1214 jbyteArray targetFile = NULL; 1216 * returned by GetByteArrayElements(). In case of a JNI
1215 1217 * error, we can't (easily) recompute the targetFile values
1216 classDef = (*jnienv)->GetObjectArrayElement(jnienv, classDefinitions, i); 1218 * and we still want to free any memory we allocated.
1217 errorOccurred = checkForThrowable(jnienv); 1219 */
1218 jplis_assert(!errorOccurred); 1220 targetFiles = (jbyteArray *) allocate(jvmtienv,
1219 if (errorOccurred) { 1221 numDefs * sizeof(jbyteArray));
1220 break; 1222 errorOccurred = (targetFiles == NULL);
1223 jplis_assert(!errorOccurred);
1224 if ( errorOccurred ) {
1225 deallocate(jvmtienv, (void*)classDefs);
1226 createAndThrowThrowableFromJVMTIErrorCode(jnienv,
1227 JVMTI_ERROR_OUT_OF_MEMORY);
1228 }
1229 else {
1230 jint i, j;
1231
1232 // clear classDefs so we can correctly free memory during errors
1233 memset(classDefs, 0, numDefs * sizeof(jvmtiClassDefinition));
1234
1235 for (i = 0; i < numDefs; i++) {
1236 jclass classDef = NULL;
1237
1238 classDef = (*jnienv)->GetObjectArrayElement(jnienv, classDefinitions, i);
1239 errorOccurred = checkForThrowable(jnienv);
1240 jplis_assert(!errorOccurred);
1241 if (errorOccurred) {
1242 break;
1243 }
1244
1245 classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID);
1246 errorOccurred = checkForThrowable(jnienv);
1247 jplis_assert(!errorOccurred);
1248 if (errorOccurred) {
1249 break;
1250 }
1251
1252 targetFiles[i] = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID);
1253 errorOccurred = checkForThrowable(jnienv);
1254 jplis_assert(!errorOccurred);
1255 if (errorOccurred) {
1256 break;
1257 }
1258
1259 classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFiles[i]);
1260 errorOccurred = checkForThrowable(jnienv);
1261 jplis_assert(!errorOccurred);
1262 if (errorOccurred) {
1263 break;
1264 }
1265
1266 /*
1267 * Allocate class_bytes last so we don't have to free
1268 * memory on a partial row error.
1269 */
1270 classDefs[i].class_bytes = (unsigned char*)(*jnienv)->GetByteArrayElements(jnienv, targetFiles[i], NULL);
1271 errorOccurred = checkForThrowable(jnienv);
1272 jplis_assert(!errorOccurred);
1273 if (errorOccurred) {
1274 break;
1275 }
1221 } 1276 }
1222 1277
1223 classDefs[i].klass = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassMethodID); 1278 if (!errorOccurred) {
1224 errorOccurred = checkForThrowable(jnienv); 1279 jvmtiError errorCode = JVMTI_ERROR_NONE;
1225 jplis_assert(!errorOccurred); 1280 errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);
1226 if (errorOccurred) { 1281 if (errorCode == JVMTI_ERROR_WRONG_PHASE) {
1227 break; 1282 /* insulate caller from the wrong phase error */
1283 errorCode = JVMTI_ERROR_NONE;
1284 } else {
1285 errorOccurred = (errorCode != JVMTI_ERROR_NONE);
1286 if ( errorOccurred ) {
1287 createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
1288 }
1289 }
1228 } 1290 }
1229 1291
1230 targetFile = (*jnienv)->CallObjectMethod(jnienv, classDef, getDefinitionClassFileMethodID); 1292 /*
1231 errorOccurred = checkForThrowable(jnienv); 1293 * Cleanup memory that we allocated above. If we had a
1232 jplis_assert(!errorOccurred); 1294 * JNI error, a JVM/TI error or no errors, index 'i'
1233 if (errorOccurred) { 1295 * tracks how far we got in processing the classDefs
1234 break; 1296 * array. Note: ReleaseByteArrayElements() is safe to
1297 * call with a JNI exception pending.
1298 */
1299 for (j = 0; j < i; j++) {
1300 if ((jbyte *)classDefs[j].class_bytes != NULL) {
1301 (*jnienv)->ReleaseByteArrayElements(jnienv,
1302 targetFiles[j], (jbyte *)classDefs[j].class_bytes,
1303 0 /* copy back and free */);
1304 /*
1305 * Only check for error if we didn't already have one
1306 * so we don't overwrite errorOccurred.
1307 */
1308 if (!errorOccurred) {
1309 errorOccurred = checkForThrowable(jnienv);
1310 jplis_assert(!errorOccurred);
1311 }
1312 }
1235 } 1313 }
1236 1314 deallocate(jvmtienv, (void*)targetFiles);
1237 classDefs[i].class_bytes = (unsigned char*)(*jnienv)->GetByteArrayElements(jnienv, targetFile, NULL); 1315 deallocate(jvmtienv, (void*)classDefs);
1238 errorOccurred = checkForThrowable(jnienv);
1239 jplis_assert(!errorOccurred);
1240 if (errorOccurred) {
1241 break;
1242 }
1243
1244 classDefs[i].class_byte_count = (*jnienv)->GetArrayLength(jnienv, targetFile);
1245 errorOccurred = checkForThrowable(jnienv);
1246 jplis_assert(!errorOccurred);
1247 if (errorOccurred) {
1248 break;
1249 }
1250 } 1316 }
1251
1252 if (!errorOccurred) {
1253 jvmtiError errorCode = JVMTI_ERROR_NONE;
1254 errorCode = (*jvmtienv)->RedefineClasses(jvmtienv, numDefs, classDefs);
1255 check_phase_blob_ret(errorCode, deallocate(jvmtienv, (void*)classDefs));
1256 errorOccurred = (errorCode != JVMTI_ERROR_NONE);
1257 if ( errorOccurred ) {
1258 createAndThrowThrowableFromJVMTIErrorCode(jnienv, errorCode);
1259 }
1260 }
1261
1262 /* Give back the buffer if we allocated it.
1263 */
1264 deallocate(jvmtienv, (void*)classDefs);
1265 } 1317 }
1266 } 1318 }
1267 1319
1268 mapThrownThrowableIfNecessary(jnienv, redefineClassMapper); 1320 mapThrownThrowableIfNecessary(jnienv, redefineClassMapper);
1269 } 1321 }