8328877: [JNI] The JNI Specification needs to address the limitations of integer UTF-8 String lengths
Reviewed-by: cjplummer, alanb
This commit is contained in:
parent
bbb516163d
commit
90f3f43257
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -19,7 +19,7 @@
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
provider hotspot_jni {
|
||||
@ -129,7 +129,7 @@ provider hotspot_jni {
|
||||
probe CallNonvirtualVoidMethodA__return();
|
||||
probe CallNonvirtualVoidMethod__entry(void*, void*, void*, uintptr_t);
|
||||
probe CallNonvirtualVoidMethod__return();
|
||||
probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t);
|
||||
probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t);
|
||||
probe CallNonvirtualVoidMethodV__return();
|
||||
probe CallObjectMethodA__entry(void*, void*, uintptr_t);
|
||||
probe CallObjectMethodA__return(void*);
|
||||
@ -200,14 +200,14 @@ provider hotspot_jni {
|
||||
probe CallStaticVoidMethodA__entry(void*, void*, uintptr_t);
|
||||
probe CallStaticVoidMethodA__return();
|
||||
probe CallStaticVoidMethod__entry(void*, void*, uintptr_t);
|
||||
probe CallStaticVoidMethod__return();
|
||||
probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t);
|
||||
probe CallStaticVoidMethod__return();
|
||||
probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t);
|
||||
probe CallStaticVoidMethodV__return();
|
||||
probe CallVoidMethodA__entry(void*, void*, uintptr_t);
|
||||
probe CallVoidMethodA__entry(void*, void*, uintptr_t);
|
||||
probe CallVoidMethodA__return();
|
||||
probe CallVoidMethod__entry(void*, void*, uintptr_t);
|
||||
probe CallVoidMethod__return();
|
||||
probe CallVoidMethodV__entry(void*, void*, uintptr_t);
|
||||
probe CallVoidMethod__entry(void*, void*, uintptr_t);
|
||||
probe CallVoidMethod__return();
|
||||
probe CallVoidMethodV__entry(void*, void*, uintptr_t);
|
||||
probe CallVoidMethodV__return();
|
||||
probe CreateJavaVM__entry(void**, void**, void*);
|
||||
probe CreateJavaVM__return(uint32_t);
|
||||
@ -229,7 +229,7 @@ provider hotspot_jni {
|
||||
probe ExceptionCheck__return(uintptr_t);
|
||||
probe ExceptionClear__entry(void*);
|
||||
probe ExceptionClear__return();
|
||||
probe ExceptionDescribe__entry(void*);
|
||||
probe ExceptionDescribe__entry(void*);
|
||||
probe ExceptionDescribe__return();
|
||||
probe ExceptionOccurred__entry(void*);
|
||||
probe ExceptionOccurred__return(void*);
|
||||
@ -352,6 +352,8 @@ provider hotspot_jni {
|
||||
probe GetStringUTFChars__return(const char*);
|
||||
probe GetStringUTFLength__entry(void*, void*);
|
||||
probe GetStringUTFLength__return(uintptr_t);
|
||||
probe GetStringUTFLengthAsLong__entry(void*, void*);
|
||||
probe GetStringUTFLengthAsLong__return(uintptr_t);
|
||||
probe GetStringUTFRegion__entry(void*, void*, uintptr_t, uintptr_t, char*);
|
||||
probe GetStringUTFRegion__return();
|
||||
probe GetSuperclass__entry(void*, void*);
|
||||
@ -388,13 +390,13 @@ provider hotspot_jni {
|
||||
probe NewLocalRef__return(void*);
|
||||
probe NewLongArray__entry(void*, uintptr_t);
|
||||
probe NewLongArray__return(void*);
|
||||
probe NewObjectA__entry(void*, void*, uintptr_t);
|
||||
probe NewObjectA__entry(void*, void*, uintptr_t);
|
||||
probe NewObjectA__return(void*);
|
||||
probe NewObjectArray__entry(void*, uintptr_t, void*, void*);
|
||||
probe NewObjectArray__return(void*);
|
||||
probe NewObject__entry(void*, void*, uintptr_t);
|
||||
probe NewObject__entry(void*, void*, uintptr_t);
|
||||
probe NewObject__return(void*);
|
||||
probe NewObjectV__entry(void*, void*, uintptr_t);
|
||||
probe NewObjectV__entry(void*, void*, uintptr_t);
|
||||
probe NewObjectV__return(void*);
|
||||
probe NewShortArray__entry(void*, uintptr_t);
|
||||
probe NewShortArray__return(void*);
|
||||
@ -408,7 +410,7 @@ provider hotspot_jni {
|
||||
probe PopLocalFrame__return(void*);
|
||||
probe PushLocalFrame__entry(void*, uint32_t);
|
||||
probe PushLocalFrame__return(uint32_t);
|
||||
probe RegisterNatives__entry(void*, void*, const void*, uint32_t);
|
||||
probe RegisterNatives__entry(void*, void*, const void*, uint32_t);
|
||||
probe RegisterNatives__return(uint32_t);
|
||||
probe ReleaseBooleanArrayElements__entry(void*, void*, uintptr_t*, uint32_t);
|
||||
probe ReleaseBooleanArrayElements__return();
|
||||
@ -490,13 +492,13 @@ provider hotspot_jni {
|
||||
probe SetStaticShortField__return();
|
||||
probe Throw__entry(void*, void*);
|
||||
probe Throw__return(intptr_t);
|
||||
probe ThrowNew__entry(void*, void*, const char*);
|
||||
probe ThrowNew__return(intptr_t);
|
||||
probe ThrowNew__entry(void*, void*, const char*);
|
||||
probe ThrowNew__return(intptr_t);
|
||||
probe ToReflectedField__entry(void*, void*, uintptr_t, uintptr_t);
|
||||
probe ToReflectedField__return(void*);
|
||||
probe ToReflectedMethod__entry(void*, void*, uintptr_t, uintptr_t);
|
||||
probe ToReflectedMethod__return(void*);
|
||||
probe UnregisterNatives__entry(void*, void*);
|
||||
probe UnregisterNatives__entry(void*, void*);
|
||||
probe UnregisterNatives__return(uint32_t);
|
||||
};
|
||||
|
||||
@ -505,4 +507,3 @@ provider hotspot_jni {
|
||||
#pragma D attributes Private/Private/Unknown provider hotspot_jni function
|
||||
#pragma D attributes Standard/Standard/Common provider hotspot_jni name
|
||||
#pragma D attributes Evolving/Evolving/Common provider hotspot_jni args
|
||||
|
||||
|
@ -102,7 +102,7 @@
|
||||
#include "jfr/jfr.hpp"
|
||||
#endif
|
||||
|
||||
static jint CurrentVersion = JNI_VERSION_21;
|
||||
static jint CurrentVersion = JNI_VERSION_24;
|
||||
|
||||
#if defined(_WIN32) && !defined(USE_VECTORED_EXCEPTION_HANDLING)
|
||||
extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* );
|
||||
@ -2221,13 +2221,21 @@ JNI_END
|
||||
|
||||
|
||||
JNI_ENTRY(jsize, jni_GetStringUTFLength(JNIEnv *env, jstring string))
|
||||
HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string);
|
||||
HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string);
|
||||
oop java_string = JNIHandles::resolve_non_null(string);
|
||||
jsize ret = java_lang_String::utf8_length_as_int(java_string);
|
||||
HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(ret);
|
||||
return ret;
|
||||
JNI_END
|
||||
|
||||
JNI_ENTRY(jlong, jni_GetStringUTFLengthAsLong(JNIEnv *env, jstring string))
|
||||
HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY(env, string);
|
||||
oop java_string = JNIHandles::resolve_non_null(string);
|
||||
size_t ret = java_lang_String::utf8_length(java_string);
|
||||
HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN(ret);
|
||||
return checked_cast<jlong>(ret);
|
||||
JNI_END
|
||||
|
||||
|
||||
JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy))
|
||||
HOTSPOT_JNI_GETSTRINGUTFCHARS_ENTRY(env, string, (uintptr_t *) isCopy);
|
||||
@ -3398,7 +3406,11 @@ struct JNINativeInterface_ jni_NativeInterface = {
|
||||
|
||||
// Virtual threads
|
||||
|
||||
jni_IsVirtualThread
|
||||
jni_IsVirtualThread,
|
||||
|
||||
// Large UTF8 support
|
||||
|
||||
jni_GetStringUTFLengthAsLong
|
||||
};
|
||||
|
||||
|
||||
|
@ -1511,6 +1511,27 @@ JNI_ENTRY_CHECKED(jsize,
|
||||
checkString(thr, str);
|
||||
)
|
||||
jsize result = UNCHECKED()->GetStringUTFLength(env,str);
|
||||
jlong full_length = UNCHECKED()->GetStringUTFLengthAsLong(env,str);
|
||||
if (full_length > result) {
|
||||
ResourceMark rm(thr);
|
||||
stringStream ss;
|
||||
ss.print("WARNING: large String with modified UTF-8 length " JLONG_FORMAT
|
||||
" is reporting a reduced length of %d - use GetStringUTFLengthAsLong instead",
|
||||
full_length, result);
|
||||
NativeReportJNIWarning(thr, ss.as_string());
|
||||
}
|
||||
functionExit(thr);
|
||||
return result;
|
||||
JNI_END
|
||||
|
||||
JNI_ENTRY_CHECKED(jlong,
|
||||
checked_jni_GetStringUTFLengthAsLong(JNIEnv *env,
|
||||
jstring str))
|
||||
functionEnter(thr);
|
||||
IN_VM(
|
||||
checkString(thr, str);
|
||||
)
|
||||
jlong result = UNCHECKED()->GetStringUTFLengthAsLong(env,str);
|
||||
functionExit(thr);
|
||||
return result;
|
||||
JNI_END
|
||||
@ -2283,7 +2304,12 @@ struct JNINativeInterface_ checked_jni_NativeInterface = {
|
||||
|
||||
// Virtual threads
|
||||
|
||||
checked_jni_IsVirtualThread
|
||||
checked_jni_IsVirtualThread,
|
||||
|
||||
// Large UTF8 support
|
||||
|
||||
checked_jni_GetStringUTFLengthAsLong
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -984,6 +984,7 @@ jboolean Threads::is_supported_jni_version(jint version) {
|
||||
if (version == JNI_VERSION_19) return JNI_TRUE;
|
||||
if (version == JNI_VERSION_20) return JNI_TRUE;
|
||||
if (version == JNI_VERSION_21) return JNI_TRUE;
|
||||
if (version == JNI_VERSION_24) return JNI_TRUE;
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -783,6 +783,10 @@
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY_ENABLED() 0
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(arg0)
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN_ENABLED() 0
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY(arg0, arg1)
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY_ENABLED() 0
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN(arg0)
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN_ENABLED() 0
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY(arg0, arg1, arg2, arg3, arg4)
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY_ENABLED() 0
|
||||
#define HOTSPOT_JNI_GETSTRINGUTFREGION_RETURN()
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -775,6 +775,12 @@ struct JNINativeInterface_ {
|
||||
|
||||
jboolean (JNICALL *IsVirtualThread)
|
||||
(JNIEnv* env, jobject obj);
|
||||
|
||||
/* Large UTF8 Support */
|
||||
|
||||
jlong (JNICALL *GetStringUTFLengthAsLong)
|
||||
(JNIEnv *env, jstring str);
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1623,6 +1629,9 @@ struct JNIEnv_ {
|
||||
jsize GetStringUTFLength(jstring str) {
|
||||
return functions->GetStringUTFLength(this,str);
|
||||
}
|
||||
jlong GetStringUTFLengthAsLong(jstring str) {
|
||||
return functions->GetStringUTFLengthAsLong(this,str);
|
||||
}
|
||||
const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
|
||||
return functions->GetStringUTFChars(this,str,isCopy);
|
||||
}
|
||||
@ -1993,6 +2002,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved);
|
||||
#define JNI_VERSION_19 0x00130000
|
||||
#define JNI_VERSION_20 0x00140000
|
||||
#define JNI_VERSION_21 0x00150000
|
||||
#define JNI_VERSION_24 0x00180000
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,12 +27,12 @@
|
||||
*/
|
||||
public class JniVersion {
|
||||
|
||||
public static final int JNI_VERSION_21 = 0x00150000;
|
||||
public static final int JNI_VERSION_24 = 0x00180000;
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
System.loadLibrary("JniVersion");
|
||||
int res = getJniVersion();
|
||||
if (res != JNI_VERSION_21) {
|
||||
if (res != JNI_VERSION_24) {
|
||||
throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8328877
|
||||
* @summary Test warning for GetStringUTFLength and functionality of GetStringUTFLengthAsLong
|
||||
* @requires vm.bits == 64
|
||||
* @library /test/lib
|
||||
* @modules java.management
|
||||
* @run main/native TestLargeUTF8Length launch
|
||||
*/
|
||||
|
||||
import java.util.Arrays;
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class TestLargeUTF8Length {
|
||||
|
||||
static {
|
||||
System.loadLibrary("TestLargeUTF8Length");
|
||||
}
|
||||
|
||||
static native void checkUTF8Length(String s, long utf8Length);
|
||||
|
||||
static void test() {
|
||||
int length = Integer.MAX_VALUE/2 + 1;
|
||||
char character = (char)0XD1; // N with tilde
|
||||
long utf8Length = 2L * length;
|
||||
char[] chrs = new char[length];
|
||||
Arrays.fill(chrs, character);
|
||||
String s = new String(chrs);
|
||||
checkUTF8Length(s, utf8Length);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (args == null || args.length == 0) {
|
||||
test();
|
||||
return;
|
||||
}
|
||||
|
||||
OutputAnalyzer oa = ProcessTools.executeTestJava("-Xms9G",
|
||||
"-Xmx9G",
|
||||
"-Xcheck:jni",
|
||||
"-Djava.library.path=" + Utils.TEST_NATIVE_PATH,
|
||||
"TestLargeUTF8Length");
|
||||
String warning = "WARNING: large String with modified UTF-8 length .*" +
|
||||
"is reporting a reduced length of .* - use GetStringUTFLengthAsLong instead";
|
||||
oa.shouldHaveExitValue(0);
|
||||
oa.stdoutShouldMatch(warning);
|
||||
oa.reportDiagnosticSummary();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_TestLargeUTF8Length_checkUTF8Length(JNIEnv *env, jclass clz,
|
||||
jstring str, jlong expected_length) {
|
||||
|
||||
jlong utf8_length;
|
||||
|
||||
// First get truncated length to generate warning
|
||||
utf8_length = (*env)->GetStringUTFLength(env, str);
|
||||
|
||||
if (utf8_length != INT_MAX - 1) {
|
||||
printf("Error: expected length of %d, but got %lld\n", INT_MAX - 1,
|
||||
(long long) utf8_length);
|
||||
(*env)->FatalError(env, "Unexpected truncated length");
|
||||
}
|
||||
|
||||
// Now get true length
|
||||
utf8_length = (*env)->GetStringUTFLengthAsLong(env, str);
|
||||
|
||||
if (utf8_length != expected_length ) {
|
||||
printf("Error: expected length of %lld, but got %lld\n",
|
||||
(long long) expected_length, (long long) utf8_length);
|
||||
(*env)->FatalError(env, "Unexpected true length");
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user