Mercurial > hg > graal-jvmci-8
comparison src/share/vm/prims/jniCheck.cpp @ 20318:fa62fb12cdca
6311046: -Xcheck:jni should support checking of GetPrimitiveArrayCritical.
Summary: Wrapped memory with standard bounds checking "GuardedMemory".
Reviewed-by: zgu, fparain, dcubed
author | dsimms |
---|---|
date | Thu, 14 Aug 2014 15:16:07 +0200 |
parents | ce8f6bb717c9 |
children | 29a5c2fd2d2e |
comparison
equal
deleted
inserted
replaced
20317:ee019285a52c | 20318:fa62fb12cdca |
---|---|
23 */ | 23 */ |
24 | 24 |
25 #include "precompiled.hpp" | 25 #include "precompiled.hpp" |
26 #include "classfile/systemDictionary.hpp" | 26 #include "classfile/systemDictionary.hpp" |
27 #include "classfile/vmSymbols.hpp" | 27 #include "classfile/vmSymbols.hpp" |
28 #include "memory/guardedMemory.hpp" | |
28 #include "oops/instanceKlass.hpp" | 29 #include "oops/instanceKlass.hpp" |
29 #include "oops/oop.inline.hpp" | 30 #include "oops/oop.inline.hpp" |
30 #include "oops/symbol.hpp" | 31 #include "oops/symbol.hpp" |
31 #include "prims/jni.h" | 32 #include "prims/jni.h" |
32 #include "prims/jniCheck.hpp" | 33 #include "prims/jniCheck.hpp" |
319 check_is_obj_array(JavaThread* thr, jarray jArray) { | 320 check_is_obj_array(JavaThread* thr, jarray jArray) { |
320 arrayOop aOop = check_is_array(thr, jArray); | 321 arrayOop aOop = check_is_array(thr, jArray); |
321 if (!aOop->is_objArray()) { | 322 if (!aOop->is_objArray()) { |
322 ReportJNIFatalError(thr, fatal_object_array_expected); | 323 ReportJNIFatalError(thr, fatal_object_array_expected); |
323 } | 324 } |
325 } | |
326 | |
327 /* | |
328 * Copy and wrap array elements for bounds checking. | |
329 * Remember the original elements (GuardedMemory::get_tag()) | |
330 */ | |
331 static void* check_jni_wrap_copy_array(JavaThread* thr, jarray array, | |
332 void* orig_elements) { | |
333 void* result; | |
334 IN_VM( | |
335 oop a = JNIHandles::resolve_non_null(array); | |
336 size_t len = arrayOop(a)->length() << | |
337 TypeArrayKlass::cast(a->klass())->log2_element_size(); | |
338 result = GuardedMemory::wrap_copy(orig_elements, len, orig_elements); | |
339 ) | |
340 return result; | |
341 } | |
342 | |
343 static void* check_wrapped_array(JavaThread* thr, const char* fn_name, | |
344 void* obj, void* carray, size_t* rsz) { | |
345 if (carray == NULL) { | |
346 tty->print_cr("%s: elements vector NULL" PTR_FORMAT, fn_name, p2i(obj)); | |
347 NativeReportJNIFatalError(thr, "Elements vector NULL"); | |
348 } | |
349 GuardedMemory guarded(carray); | |
350 void* orig_result = guarded.get_tag(); | |
351 if (!guarded.verify_guards()) { | |
352 tty->print_cr("ReleasePrimitiveArrayCritical: release array failed bounds " | |
353 "check, incorrect pointer returned ? array: " PTR_FORMAT " carray: " | |
354 PTR_FORMAT, p2i(obj), p2i(carray)); | |
355 guarded.print_on(tty); | |
356 NativeReportJNIFatalError(thr, "ReleasePrimitiveArrayCritical: " | |
357 "failed bounds check"); | |
358 } | |
359 if (orig_result == NULL) { | |
360 tty->print_cr("ReleasePrimitiveArrayCritical: unrecognized elements. array: " | |
361 PTR_FORMAT " carray: " PTR_FORMAT, p2i(obj), p2i(carray)); | |
362 guarded.print_on(tty); | |
363 NativeReportJNIFatalError(thr, "ReleasePrimitiveArrayCritical: " | |
364 "unrecognized elements"); | |
365 } | |
366 if (rsz != NULL) { | |
367 *rsz = guarded.get_user_size(); | |
368 } | |
369 return orig_result; | |
370 } | |
371 | |
372 static void* check_wrapped_array_release(JavaThread* thr, const char* fn_name, | |
373 void* obj, void* carray, jint mode) { | |
374 size_t sz; | |
375 void* orig_result = check_wrapped_array(thr, fn_name, obj, carray, &sz); | |
376 switch (mode) { | |
377 case 0: | |
378 memcpy(orig_result, carray, sz); | |
379 GuardedMemory::free_copy(carray); | |
380 break; | |
381 case JNI_COMMIT: | |
382 memcpy(orig_result, carray, sz); | |
383 break; | |
384 case JNI_ABORT: | |
385 GuardedMemory::free_copy(carray); | |
386 break; | |
387 default: | |
388 tty->print_cr("%s: Unrecognized mode %i releasing array " | |
389 PTR_FORMAT " elements " PTR_FORMAT, fn_name, mode, p2i(obj), p2i(carray)); | |
390 NativeReportJNIFatalError(thr, "Unrecognized array release mode"); | |
391 } | |
392 return orig_result; | |
324 } | 393 } |
325 | 394 |
326 oop jniCheck::validate_handle(JavaThread* thr, jobject obj) { | 395 oop jniCheck::validate_handle(JavaThread* thr, jobject obj) { |
327 if (JNIHandles::is_frame_handle(thr, obj) || | 396 if (JNIHandles::is_frame_handle(thr, obj) || |
328 JNIHandles::is_local_handle(thr, obj) || | 397 JNIHandles::is_local_handle(thr, obj) || |
1312 functionExit(env); | 1381 functionExit(env); |
1313 return result; | 1382 return result; |
1314 JNI_END | 1383 JNI_END |
1315 | 1384 |
1316 // Arbitrary (but well-known) tag | 1385 // Arbitrary (but well-known) tag |
1317 const jint STRING_TAG = 0x47114711; | 1386 const void* STRING_TAG = (void*)0x47114711; |
1318 | 1387 |
1319 JNI_ENTRY_CHECKED(const jchar *, | 1388 JNI_ENTRY_CHECKED(const jchar *, |
1320 checked_jni_GetStringChars(JNIEnv *env, | 1389 checked_jni_GetStringChars(JNIEnv *env, |
1321 jstring str, | 1390 jstring str, |
1322 jboolean *isCopy)) | 1391 jboolean *isCopy)) |
1323 functionEnter(thr); | 1392 functionEnter(thr); |
1324 IN_VM( | 1393 IN_VM( |
1325 checkString(thr, str); | 1394 checkString(thr, str); |
1326 ) | 1395 ) |
1327 jchar* newResult = NULL; | 1396 jchar* new_result = NULL; |
1328 const jchar *result = UNCHECKED()->GetStringChars(env,str,isCopy); | 1397 const jchar *result = UNCHECKED()->GetStringChars(env,str,isCopy); |
1329 assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringChars didn't return a copy as expected"); | 1398 assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringChars didn't return a copy as expected"); |
1330 if (result != NULL) { | 1399 if (result != NULL) { |
1331 size_t len = UNCHECKED()->GetStringLength(env,str) + 1; // + 1 for NULL termination | 1400 size_t len = UNCHECKED()->GetStringLength(env,str) + 1; // + 1 for NULL termination |
1332 jint* tagLocation = (jint*) AllocateHeap(len * sizeof(jchar) + sizeof(jint), mtInternal); | 1401 len *= sizeof(jchar); |
1333 *tagLocation = STRING_TAG; | 1402 new_result = (jchar*) GuardedMemory::wrap_copy(result, len, STRING_TAG); |
1334 newResult = (jchar*) (tagLocation + 1); | 1403 if (new_result == NULL) { |
1335 memcpy(newResult, result, len * sizeof(jchar)); | 1404 vm_exit_out_of_memory(len, OOM_MALLOC_ERROR, "checked_jni_GetStringChars"); |
1405 } | |
1336 // Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes | 1406 // Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes |
1337 // Note that the dtrace arguments for the allocated memory will not match up with this solution. | 1407 // Note that the dtrace arguments for the allocated memory will not match up with this solution. |
1338 FreeHeap((char*)result); | 1408 FreeHeap((char*)result); |
1339 } | 1409 } |
1340 functionExit(env); | 1410 functionExit(env); |
1341 return newResult; | 1411 return new_result; |
1342 JNI_END | 1412 JNI_END |
1343 | 1413 |
1344 JNI_ENTRY_CHECKED(void, | 1414 JNI_ENTRY_CHECKED(void, |
1345 checked_jni_ReleaseStringChars(JNIEnv *env, | 1415 checked_jni_ReleaseStringChars(JNIEnv *env, |
1346 jstring str, | 1416 jstring str, |
1352 if (chars == NULL) { | 1422 if (chars == NULL) { |
1353 // still do the unchecked call to allow dtrace probes | 1423 // still do the unchecked call to allow dtrace probes |
1354 UNCHECKED()->ReleaseStringChars(env,str,chars); | 1424 UNCHECKED()->ReleaseStringChars(env,str,chars); |
1355 } | 1425 } |
1356 else { | 1426 else { |
1357 jint* tagLocation = ((jint*) chars) - 1; | 1427 GuardedMemory guarded((void*)chars); |
1358 if (*tagLocation != STRING_TAG) { | 1428 if (guarded.verify_guards()) { |
1359 NativeReportJNIFatalError(thr, "ReleaseStringChars called on something not allocated by GetStringChars"); | 1429 tty->print_cr("ReleaseStringChars: release chars failed bounds check. " |
1360 } | 1430 "string: " PTR_FORMAT " chars: " PTR_FORMAT, p2i(str), p2i(chars)); |
1361 UNCHECKED()->ReleaseStringChars(env,str,(const jchar*)tagLocation); | 1431 guarded.print_on(tty); |
1432 NativeReportJNIFatalError(thr, "ReleaseStringChars: " | |
1433 "release chars failed bounds check."); | |
1434 } | |
1435 if (guarded.get_tag() != STRING_TAG) { | |
1436 tty->print_cr("ReleaseStringChars: called on something not allocated " | |
1437 "by GetStringChars. string: " PTR_FORMAT " chars: " PTR_FORMAT, | |
1438 p2i(str), p2i(chars)); | |
1439 NativeReportJNIFatalError(thr, "ReleaseStringChars called on something " | |
1440 "not allocated by GetStringChars"); | |
1441 } | |
1442 UNCHECKED()->ReleaseStringChars(env, str, | |
1443 (const jchar*) guarded.release_for_freeing()); | |
1362 } | 1444 } |
1363 functionExit(env); | 1445 functionExit(env); |
1364 JNI_END | 1446 JNI_END |
1365 | 1447 |
1366 JNI_ENTRY_CHECKED(jstring, | 1448 JNI_ENTRY_CHECKED(jstring, |
1383 functionExit(env); | 1465 functionExit(env); |
1384 return result; | 1466 return result; |
1385 JNI_END | 1467 JNI_END |
1386 | 1468 |
1387 // Arbitrary (but well-known) tag - different than GetStringChars | 1469 // Arbitrary (but well-known) tag - different than GetStringChars |
1388 const jint STRING_UTF_TAG = 0x48124812; | 1470 const void* STRING_UTF_TAG = (void*) 0x48124812; |
1389 | 1471 |
1390 JNI_ENTRY_CHECKED(const char *, | 1472 JNI_ENTRY_CHECKED(const char *, |
1391 checked_jni_GetStringUTFChars(JNIEnv *env, | 1473 checked_jni_GetStringUTFChars(JNIEnv *env, |
1392 jstring str, | 1474 jstring str, |
1393 jboolean *isCopy)) | 1475 jboolean *isCopy)) |
1394 functionEnter(thr); | 1476 functionEnter(thr); |
1395 IN_VM( | 1477 IN_VM( |
1396 checkString(thr, str); | 1478 checkString(thr, str); |
1397 ) | 1479 ) |
1398 char* newResult = NULL; | 1480 char* new_result = NULL; |
1399 const char *result = UNCHECKED()->GetStringUTFChars(env,str,isCopy); | 1481 const char *result = UNCHECKED()->GetStringUTFChars(env,str,isCopy); |
1400 assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringUTFChars didn't return a copy as expected"); | 1482 assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringUTFChars didn't return a copy as expected"); |
1401 if (result != NULL) { | 1483 if (result != NULL) { |
1402 size_t len = strlen(result) + 1; // + 1 for NULL termination | 1484 size_t len = strlen(result) + 1; // + 1 for NULL termination |
1403 jint* tagLocation = (jint*) AllocateHeap(len + sizeof(jint), mtInternal); | 1485 new_result = (char*) GuardedMemory::wrap_copy(result, len, STRING_UTF_TAG); |
1404 *tagLocation = STRING_UTF_TAG; | 1486 if (new_result == NULL) { |
1405 newResult = (char*) (tagLocation + 1); | 1487 vm_exit_out_of_memory(len, OOM_MALLOC_ERROR, "checked_jni_GetStringUTFChars"); |
1406 strcpy(newResult, result); | 1488 } |
1407 // Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes | 1489 // Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes |
1408 // Note that the dtrace arguments for the allocated memory will not match up with this solution. | 1490 // Note that the dtrace arguments for the allocated memory will not match up with this solution. |
1409 FreeHeap((char*)result, mtInternal); | 1491 FreeHeap((char*)result, mtInternal); |
1410 } | 1492 } |
1411 functionExit(env); | 1493 functionExit(env); |
1412 return newResult; | 1494 return new_result; |
1413 JNI_END | 1495 JNI_END |
1414 | 1496 |
1415 JNI_ENTRY_CHECKED(void, | 1497 JNI_ENTRY_CHECKED(void, |
1416 checked_jni_ReleaseStringUTFChars(JNIEnv *env, | 1498 checked_jni_ReleaseStringUTFChars(JNIEnv *env, |
1417 jstring str, | 1499 jstring str, |
1423 if (chars == NULL) { | 1505 if (chars == NULL) { |
1424 // still do the unchecked call to allow dtrace probes | 1506 // still do the unchecked call to allow dtrace probes |
1425 UNCHECKED()->ReleaseStringUTFChars(env,str,chars); | 1507 UNCHECKED()->ReleaseStringUTFChars(env,str,chars); |
1426 } | 1508 } |
1427 else { | 1509 else { |
1428 jint* tagLocation = ((jint*) chars) - 1; | 1510 GuardedMemory guarded((void*)chars); |
1429 if (*tagLocation != STRING_UTF_TAG) { | 1511 if (guarded.verify_guards()) { |
1430 NativeReportJNIFatalError(thr, "ReleaseStringUTFChars called on something not allocated by GetStringUTFChars"); | 1512 tty->print_cr("ReleaseStringUTFChars: release chars failed bounds check. " |
1431 } | 1513 "string: " PTR_FORMAT " chars: " PTR_FORMAT, p2i(str), p2i(chars)); |
1432 UNCHECKED()->ReleaseStringUTFChars(env,str,(const char*)tagLocation); | 1514 guarded.print_on(tty); |
1515 NativeReportJNIFatalError(thr, "ReleaseStringUTFChars: " | |
1516 "release chars failed bounds check."); | |
1517 } | |
1518 if (guarded.get_tag() != STRING_UTF_TAG) { | |
1519 tty->print_cr("ReleaseStringUTFChars: called on something not " | |
1520 "allocated by GetStringUTFChars. string: " PTR_FORMAT " chars: " | |
1521 PTR_FORMAT, p2i(str), p2i(chars)); | |
1522 NativeReportJNIFatalError(thr, "ReleaseStringUTFChars " | |
1523 "called on something not allocated by GetStringUTFChars"); | |
1524 } | |
1525 UNCHECKED()->ReleaseStringUTFChars(env, str, | |
1526 (const char*) guarded.release_for_freeing()); | |
1433 } | 1527 } |
1434 functionExit(env); | 1528 functionExit(env); |
1435 JNI_END | 1529 JNI_END |
1436 | 1530 |
1437 JNI_ENTRY_CHECKED(jsize, | 1531 JNI_ENTRY_CHECKED(jsize, |
1512 check_primitive_array_type(thr, array, ElementTag); \ | 1606 check_primitive_array_type(thr, array, ElementTag); \ |
1513 ) \ | 1607 ) \ |
1514 ElementType *result = UNCHECKED()->Get##Result##ArrayElements(env, \ | 1608 ElementType *result = UNCHECKED()->Get##Result##ArrayElements(env, \ |
1515 array, \ | 1609 array, \ |
1516 isCopy); \ | 1610 isCopy); \ |
1611 if (result != NULL) { \ | |
1612 result = (ElementType *) check_jni_wrap_copy_array(thr, array, result); \ | |
1613 } \ | |
1517 functionExit(env); \ | 1614 functionExit(env); \ |
1518 return result; \ | 1615 return result; \ |
1519 JNI_END | 1616 JNI_END |
1520 | 1617 |
1521 WRAPPER_GetScalarArrayElements(T_BOOLEAN, jboolean, Boolean) | 1618 WRAPPER_GetScalarArrayElements(T_BOOLEAN, jboolean, Boolean) |
1536 functionEnterExceptionAllowed(thr); \ | 1633 functionEnterExceptionAllowed(thr); \ |
1537 IN_VM( \ | 1634 IN_VM( \ |
1538 check_primitive_array_type(thr, array, ElementTag); \ | 1635 check_primitive_array_type(thr, array, ElementTag); \ |
1539 ASSERT_OOPS_ALLOWED; \ | 1636 ASSERT_OOPS_ALLOWED; \ |
1540 typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array)); \ | 1637 typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array)); \ |
1541 /* cannot check validity of copy, unless every request is logged by | |
1542 * checking code. Implementation of this check is deferred until a | |
1543 * subsequent release. | |
1544 */ \ | |
1545 ) \ | 1638 ) \ |
1546 UNCHECKED()->Release##Result##ArrayElements(env,array,elems,mode); \ | 1639 ElementType* orig_result = (ElementType *) check_wrapped_array_release( \ |
1640 thr, "checked_jni_Release"#Result"ArrayElements", array, elems, mode); \ | |
1641 UNCHECKED()->Release##Result##ArrayElements(env, array, orig_result, mode); \ | |
1547 functionExit(env); \ | 1642 functionExit(env); \ |
1548 JNI_END | 1643 JNI_END |
1549 | 1644 |
1550 WRAPPER_ReleaseScalarArrayElements(T_BOOLEAN,jboolean, Boolean, bool) | 1645 WRAPPER_ReleaseScalarArrayElements(T_BOOLEAN,jboolean, Boolean, bool) |
1551 WRAPPER_ReleaseScalarArrayElements(T_BYTE, jbyte, Byte, byte) | 1646 WRAPPER_ReleaseScalarArrayElements(T_BYTE, jbyte, Byte, byte) |
1692 functionEnterCritical(thr); | 1787 functionEnterCritical(thr); |
1693 IN_VM( | 1788 IN_VM( |
1694 check_is_primitive_array(thr, array); | 1789 check_is_primitive_array(thr, array); |
1695 ) | 1790 ) |
1696 void *result = UNCHECKED()->GetPrimitiveArrayCritical(env, array, isCopy); | 1791 void *result = UNCHECKED()->GetPrimitiveArrayCritical(env, array, isCopy); |
1792 if (result != NULL) { | |
1793 result = check_jni_wrap_copy_array(thr, array, result); | |
1794 } | |
1697 functionExit(env); | 1795 functionExit(env); |
1698 return result; | 1796 return result; |
1699 JNI_END | 1797 JNI_END |
1700 | 1798 |
1701 JNI_ENTRY_CHECKED(void, | 1799 JNI_ENTRY_CHECKED(void, |
1705 jint mode)) | 1803 jint mode)) |
1706 functionEnterCriticalExceptionAllowed(thr); | 1804 functionEnterCriticalExceptionAllowed(thr); |
1707 IN_VM( | 1805 IN_VM( |
1708 check_is_primitive_array(thr, array); | 1806 check_is_primitive_array(thr, array); |
1709 ) | 1807 ) |
1710 /* The Hotspot JNI code does not use the parameters, so just check the | 1808 // Check the element array... |
1711 * array parameter as a minor sanity check | 1809 void* orig_result = check_wrapped_array_release(thr, "ReleasePrimitiveArrayCritical", array, carray, mode); |
1712 */ | 1810 UNCHECKED()->ReleasePrimitiveArrayCritical(env, array, orig_result, mode); |
1713 UNCHECKED()->ReleasePrimitiveArrayCritical(env, array, carray, mode); | |
1714 functionExit(env); | 1811 functionExit(env); |
1715 JNI_END | 1812 JNI_END |
1716 | 1813 |
1717 JNI_ENTRY_CHECKED(const jchar*, | 1814 JNI_ENTRY_CHECKED(const jchar*, |
1718 checked_jni_GetStringCritical(JNIEnv *env, | 1815 checked_jni_GetStringCritical(JNIEnv *env, |