mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
6539281: -Xcheck:jni should validate char* argument to ReleaseStringUTFChars
Tag allocated memory with a magic value and verify when releasing. Reviewed-by: phh, stefank
This commit is contained in:
parent
dd62e29b29
commit
1765b0fbf0
4 changed files with 65 additions and 17 deletions
|
@ -313,6 +313,14 @@ char* java_lang_String::as_utf8_string(oop java_string) {
|
||||||
return UNICODE::as_utf8(position, length);
|
return UNICODE::as_utf8(position, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* java_lang_String::as_utf8_string(oop java_string, char* buf, int buflen) {
|
||||||
|
typeArrayOop value = java_lang_String::value(java_string);
|
||||||
|
int offset = java_lang_String::offset(java_string);
|
||||||
|
int length = java_lang_String::length(java_string);
|
||||||
|
jchar* position = (length == 0) ? NULL : value->char_at_addr(offset);
|
||||||
|
return UNICODE::as_utf8(position, length, buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
char* java_lang_String::as_utf8_string(oop java_string, int start, int len) {
|
char* java_lang_String::as_utf8_string(oop java_string, int start, int len) {
|
||||||
typeArrayOop value = java_lang_String::value(java_string);
|
typeArrayOop value = java_lang_String::value(java_string);
|
||||||
int offset = java_lang_String::offset(java_string);
|
int offset = java_lang_String::offset(java_string);
|
||||||
|
|
|
@ -104,6 +104,7 @@ class java_lang_String : AllStatic {
|
||||||
|
|
||||||
// String converters
|
// String converters
|
||||||
static char* as_utf8_string(oop java_string);
|
static char* as_utf8_string(oop java_string);
|
||||||
|
static char* as_utf8_string(oop java_string, char* buf, int buflen);
|
||||||
static char* as_utf8_string(oop java_string, int start, int len);
|
static char* as_utf8_string(oop java_string, int start, int len);
|
||||||
static char* as_platform_dependent_str(Handle java_string, TRAPS);
|
static char* as_platform_dependent_str(Handle java_string, TRAPS);
|
||||||
static jchar* as_unicode_string(oop java_string, int& length);
|
static jchar* as_unicode_string(oop java_string, int& length);
|
||||||
|
|
|
@ -2113,11 +2113,10 @@ JNI_END
|
||||||
JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy))
|
JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy))
|
||||||
JNIWrapper("GetStringUTFChars");
|
JNIWrapper("GetStringUTFChars");
|
||||||
DTRACE_PROBE3(hotspot_jni, GetStringUTFChars__entry, env, string, isCopy);
|
DTRACE_PROBE3(hotspot_jni, GetStringUTFChars__entry, env, string, isCopy);
|
||||||
ResourceMark rm;
|
oop java_string = JNIHandles::resolve_non_null(string);
|
||||||
char* str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(string));
|
size_t length = java_lang_String::utf8_length(java_string);
|
||||||
int length = (int)strlen(str);
|
char* result = AllocateHeap(length + 1, "GetStringUTFChars");
|
||||||
char* result = AllocateHeap(length+1, "GetStringUTFChars");
|
java_lang_String::as_utf8_string(java_string, result, (int) length + 1);
|
||||||
strcpy(result, str);
|
|
||||||
if (isCopy != NULL) *isCopy = JNI_TRUE;
|
if (isCopy != NULL) *isCopy = JNI_TRUE;
|
||||||
DTRACE_PROBE1(hotspot_jni, GetStringUTFChars__return, result);
|
DTRACE_PROBE1(hotspot_jni, GetStringUTFChars__return, result);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1288,6 +1288,9 @@ JNI_ENTRY_CHECKED(jsize,
|
||||||
return result;
|
return result;
|
||||||
JNI_END
|
JNI_END
|
||||||
|
|
||||||
|
// Arbitrary (but well-known) tag
|
||||||
|
const jint STRING_TAG = 0x47114711;
|
||||||
|
|
||||||
JNI_ENTRY_CHECKED(const jchar *,
|
JNI_ENTRY_CHECKED(const jchar *,
|
||||||
checked_jni_GetStringChars(JNIEnv *env,
|
checked_jni_GetStringChars(JNIEnv *env,
|
||||||
jstring str,
|
jstring str,
|
||||||
|
@ -1297,8 +1300,19 @@ JNI_ENTRY_CHECKED(const jchar *,
|
||||||
checkString(thr, str);
|
checkString(thr, str);
|
||||||
)
|
)
|
||||||
const jchar *result = UNCHECKED()->GetStringChars(env,str,isCopy);
|
const jchar *result = UNCHECKED()->GetStringChars(env,str,isCopy);
|
||||||
|
assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringChars didn't return a copy as expected");
|
||||||
|
|
||||||
|
size_t len = UNCHECKED()->GetStringLength(env,str) + 1; // + 1 for NULL termination
|
||||||
|
jint* tagLocation = (jint*) AllocateHeap(len * sizeof(jchar) + sizeof(jint), "checked_jni_GetStringChars");
|
||||||
|
*tagLocation = STRING_TAG;
|
||||||
|
jchar* newResult = (jchar*) (tagLocation + 1);
|
||||||
|
memcpy(newResult, result, len * sizeof(jchar));
|
||||||
|
// Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes
|
||||||
|
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
|
||||||
|
FreeHeap((char*)result);
|
||||||
|
|
||||||
functionExit(env);
|
functionExit(env);
|
||||||
return result;
|
return newResult;
|
||||||
JNI_END
|
JNI_END
|
||||||
|
|
||||||
JNI_ENTRY_CHECKED(void,
|
JNI_ENTRY_CHECKED(void,
|
||||||
|
@ -1309,11 +1323,17 @@ JNI_ENTRY_CHECKED(void,
|
||||||
IN_VM(
|
IN_VM(
|
||||||
checkString(thr, str);
|
checkString(thr, str);
|
||||||
)
|
)
|
||||||
/* cannot check validity of copy, unless every request is logged by
|
if (chars == NULL) {
|
||||||
* checking code. Implementation of this check is deferred until a
|
// still do the unchecked call to allow dtrace probes
|
||||||
* subsequent release.
|
UNCHECKED()->ReleaseStringChars(env,str,chars);
|
||||||
*/
|
}
|
||||||
UNCHECKED()->ReleaseStringChars(env,str,chars);
|
else {
|
||||||
|
jint* tagLocation = ((jint*) chars) - 1;
|
||||||
|
if (*tagLocation != STRING_TAG) {
|
||||||
|
NativeReportJNIFatalError(thr, "ReleaseStringChars called on something not allocated by GetStringChars");
|
||||||
|
}
|
||||||
|
UNCHECKED()->ReleaseStringChars(env,str,(const jchar*)tagLocation);
|
||||||
|
}
|
||||||
functionExit(env);
|
functionExit(env);
|
||||||
JNI_END
|
JNI_END
|
||||||
|
|
||||||
|
@ -1338,6 +1358,9 @@ JNI_ENTRY_CHECKED(jsize,
|
||||||
return result;
|
return result;
|
||||||
JNI_END
|
JNI_END
|
||||||
|
|
||||||
|
// Arbitrary (but well-known) tag - different than GetStringChars
|
||||||
|
const jint STRING_UTF_TAG = 0x48124812;
|
||||||
|
|
||||||
JNI_ENTRY_CHECKED(const char *,
|
JNI_ENTRY_CHECKED(const char *,
|
||||||
checked_jni_GetStringUTFChars(JNIEnv *env,
|
checked_jni_GetStringUTFChars(JNIEnv *env,
|
||||||
jstring str,
|
jstring str,
|
||||||
|
@ -1347,8 +1370,19 @@ JNI_ENTRY_CHECKED(const char *,
|
||||||
checkString(thr, str);
|
checkString(thr, str);
|
||||||
)
|
)
|
||||||
const char *result = UNCHECKED()->GetStringUTFChars(env,str,isCopy);
|
const char *result = UNCHECKED()->GetStringUTFChars(env,str,isCopy);
|
||||||
|
assert (isCopy == NULL || *isCopy == JNI_TRUE, "GetStringUTFChars didn't return a copy as expected");
|
||||||
|
|
||||||
|
size_t len = strlen(result) + 1; // + 1 for NULL termination
|
||||||
|
jint* tagLocation = (jint*) AllocateHeap(len + sizeof(jint), "checked_jni_GetStringUTFChars");
|
||||||
|
*tagLocation = STRING_UTF_TAG;
|
||||||
|
char* newResult = (char*) (tagLocation + 1);
|
||||||
|
strcpy(newResult, result);
|
||||||
|
// Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes
|
||||||
|
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
|
||||||
|
FreeHeap((char*)result);
|
||||||
|
|
||||||
functionExit(env);
|
functionExit(env);
|
||||||
return result;
|
return newResult;
|
||||||
JNI_END
|
JNI_END
|
||||||
|
|
||||||
JNI_ENTRY_CHECKED(void,
|
JNI_ENTRY_CHECKED(void,
|
||||||
|
@ -1359,11 +1393,17 @@ JNI_ENTRY_CHECKED(void,
|
||||||
IN_VM(
|
IN_VM(
|
||||||
checkString(thr, str);
|
checkString(thr, str);
|
||||||
)
|
)
|
||||||
/* cannot check validity of copy, unless every request is logged by
|
if (chars == NULL) {
|
||||||
* checking code. Implementation of this check is deferred until a
|
// still do the unchecked call to allow dtrace probes
|
||||||
* subsequent release.
|
UNCHECKED()->ReleaseStringUTFChars(env,str,chars);
|
||||||
*/
|
}
|
||||||
UNCHECKED()->ReleaseStringUTFChars(env,str,chars);
|
else {
|
||||||
|
jint* tagLocation = ((jint*) chars) - 1;
|
||||||
|
if (*tagLocation != STRING_UTF_TAG) {
|
||||||
|
NativeReportJNIFatalError(thr, "ReleaseStringUTFChars called on something not allocated by GetStringUTFChars");
|
||||||
|
}
|
||||||
|
UNCHECKED()->ReleaseStringUTFChars(env,str,(const char*)tagLocation);
|
||||||
|
}
|
||||||
functionExit(env);
|
functionExit(env);
|
||||||
JNI_END
|
JNI_END
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue