Skip to content

Commit 0affb69

Browse files
David Holmespull[bot]
David Holmes
authored andcommitted
8328877: [JNI] The JNI Specification needs to address the limitations of integer UTF-8 String lengths
Reviewed-by: cjplummer, alanb
1 parent 0f24b57 commit 0affb69

File tree

9 files changed

+208
-27
lines changed

9 files changed

+208
-27
lines changed

src/hotspot/os/posix/dtrace/hotspot_jni.d

+19-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2024, 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
@@ -19,7 +19,7 @@
1919
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2020
* or visit www.oracle.com if you need additional information or have any
2121
* questions.
22-
*
22+
*
2323
*/
2424

2525
provider hotspot_jni {
@@ -129,7 +129,7 @@ provider hotspot_jni {
129129
probe CallNonvirtualVoidMethodA__return();
130130
probe CallNonvirtualVoidMethod__entry(void*, void*, void*, uintptr_t);
131131
probe CallNonvirtualVoidMethod__return();
132-
probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t);
132+
probe CallNonvirtualVoidMethodV__entry(void*, void*, void*, uintptr_t);
133133
probe CallNonvirtualVoidMethodV__return();
134134
probe CallObjectMethodA__entry(void*, void*, uintptr_t);
135135
probe CallObjectMethodA__return(void*);
@@ -200,14 +200,14 @@ provider hotspot_jni {
200200
probe CallStaticVoidMethodA__entry(void*, void*, uintptr_t);
201201
probe CallStaticVoidMethodA__return();
202202
probe CallStaticVoidMethod__entry(void*, void*, uintptr_t);
203-
probe CallStaticVoidMethod__return();
204-
probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t);
203+
probe CallStaticVoidMethod__return();
204+
probe CallStaticVoidMethodV__entry(void*, void*, uintptr_t);
205205
probe CallStaticVoidMethodV__return();
206-
probe CallVoidMethodA__entry(void*, void*, uintptr_t);
206+
probe CallVoidMethodA__entry(void*, void*, uintptr_t);
207207
probe CallVoidMethodA__return();
208-
probe CallVoidMethod__entry(void*, void*, uintptr_t);
209-
probe CallVoidMethod__return();
210-
probe CallVoidMethodV__entry(void*, void*, uintptr_t);
208+
probe CallVoidMethod__entry(void*, void*, uintptr_t);
209+
probe CallVoidMethod__return();
210+
probe CallVoidMethodV__entry(void*, void*, uintptr_t);
211211
probe CallVoidMethodV__return();
212212
probe CreateJavaVM__entry(void**, void**, void*);
213213
probe CreateJavaVM__return(uint32_t);
@@ -229,7 +229,7 @@ provider hotspot_jni {
229229
probe ExceptionCheck__return(uintptr_t);
230230
probe ExceptionClear__entry(void*);
231231
probe ExceptionClear__return();
232-
probe ExceptionDescribe__entry(void*);
232+
probe ExceptionDescribe__entry(void*);
233233
probe ExceptionDescribe__return();
234234
probe ExceptionOccurred__entry(void*);
235235
probe ExceptionOccurred__return(void*);
@@ -352,6 +352,8 @@ provider hotspot_jni {
352352
probe GetStringUTFChars__return(const char*);
353353
probe GetStringUTFLength__entry(void*, void*);
354354
probe GetStringUTFLength__return(uintptr_t);
355+
probe GetStringUTFLengthAsLong__entry(void*, void*);
356+
probe GetStringUTFLengthAsLong__return(uintptr_t);
355357
probe GetStringUTFRegion__entry(void*, void*, uintptr_t, uintptr_t, char*);
356358
probe GetStringUTFRegion__return();
357359
probe GetSuperclass__entry(void*, void*);
@@ -388,13 +390,13 @@ provider hotspot_jni {
388390
probe NewLocalRef__return(void*);
389391
probe NewLongArray__entry(void*, uintptr_t);
390392
probe NewLongArray__return(void*);
391-
probe NewObjectA__entry(void*, void*, uintptr_t);
393+
probe NewObjectA__entry(void*, void*, uintptr_t);
392394
probe NewObjectA__return(void*);
393395
probe NewObjectArray__entry(void*, uintptr_t, void*, void*);
394396
probe NewObjectArray__return(void*);
395-
probe NewObject__entry(void*, void*, uintptr_t);
397+
probe NewObject__entry(void*, void*, uintptr_t);
396398
probe NewObject__return(void*);
397-
probe NewObjectV__entry(void*, void*, uintptr_t);
399+
probe NewObjectV__entry(void*, void*, uintptr_t);
398400
probe NewObjectV__return(void*);
399401
probe NewShortArray__entry(void*, uintptr_t);
400402
probe NewShortArray__return(void*);
@@ -408,7 +410,7 @@ provider hotspot_jni {
408410
probe PopLocalFrame__return(void*);
409411
probe PushLocalFrame__entry(void*, uint32_t);
410412
probe PushLocalFrame__return(uint32_t);
411-
probe RegisterNatives__entry(void*, void*, const void*, uint32_t);
413+
probe RegisterNatives__entry(void*, void*, const void*, uint32_t);
412414
probe RegisterNatives__return(uint32_t);
413415
probe ReleaseBooleanArrayElements__entry(void*, void*, uintptr_t*, uint32_t);
414416
probe ReleaseBooleanArrayElements__return();
@@ -490,13 +492,13 @@ provider hotspot_jni {
490492
probe SetStaticShortField__return();
491493
probe Throw__entry(void*, void*);
492494
probe Throw__return(intptr_t);
493-
probe ThrowNew__entry(void*, void*, const char*);
494-
probe ThrowNew__return(intptr_t);
495+
probe ThrowNew__entry(void*, void*, const char*);
496+
probe ThrowNew__return(intptr_t);
495497
probe ToReflectedField__entry(void*, void*, uintptr_t, uintptr_t);
496498
probe ToReflectedField__return(void*);
497499
probe ToReflectedMethod__entry(void*, void*, uintptr_t, uintptr_t);
498500
probe ToReflectedMethod__return(void*);
499-
probe UnregisterNatives__entry(void*, void*);
501+
probe UnregisterNatives__entry(void*, void*);
500502
probe UnregisterNatives__return(uint32_t);
501503
};
502504

@@ -505,4 +507,3 @@ provider hotspot_jni {
505507
#pragma D attributes Private/Private/Unknown provider hotspot_jni function
506508
#pragma D attributes Standard/Standard/Common provider hotspot_jni name
507509
#pragma D attributes Evolving/Evolving/Common provider hotspot_jni args
508-

src/hotspot/share/prims/jni.cpp

+15-3
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
#include "jfr/jfr.hpp"
103103
#endif
104104

105-
static jint CurrentVersion = JNI_VERSION_21;
105+
static jint CurrentVersion = JNI_VERSION_24;
106106

107107
#if defined(_WIN32) && !defined(USE_VECTORED_EXCEPTION_HANDLING)
108108
extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* );
@@ -2221,13 +2221,21 @@ JNI_END
22212221

22222222

22232223
JNI_ENTRY(jsize, jni_GetStringUTFLength(JNIEnv *env, jstring string))
2224-
HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string);
2224+
HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string);
22252225
oop java_string = JNIHandles::resolve_non_null(string);
22262226
jsize ret = java_lang_String::utf8_length_as_int(java_string);
22272227
HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(ret);
22282228
return ret;
22292229
JNI_END
22302230

2231+
JNI_ENTRY(jlong, jni_GetStringUTFLengthAsLong(JNIEnv *env, jstring string))
2232+
HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY(env, string);
2233+
oop java_string = JNIHandles::resolve_non_null(string);
2234+
size_t ret = java_lang_String::utf8_length(java_string);
2235+
HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN(ret);
2236+
return checked_cast<jlong>(ret);
2237+
JNI_END
2238+
22312239

22322240
JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy))
22332241
HOTSPOT_JNI_GETSTRINGUTFCHARS_ENTRY(env, string, (uintptr_t *) isCopy);
@@ -3398,7 +3406,11 @@ struct JNINativeInterface_ jni_NativeInterface = {
33983406

33993407
// Virtual threads
34003408

3401-
jni_IsVirtualThread
3409+
jni_IsVirtualThread,
3410+
3411+
// Large UTF8 support
3412+
3413+
jni_GetStringUTFLengthAsLong
34023414
};
34033415

34043416

src/hotspot/share/prims/jniCheck.cpp

+27-1
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,27 @@ JNI_ENTRY_CHECKED(jsize,
15111511
checkString(thr, str);
15121512
)
15131513
jsize result = UNCHECKED()->GetStringUTFLength(env,str);
1514+
jlong full_length = UNCHECKED()->GetStringUTFLengthAsLong(env,str);
1515+
if (full_length > result) {
1516+
ResourceMark rm(thr);
1517+
stringStream ss;
1518+
ss.print("WARNING: large String with modified UTF-8 length " JLONG_FORMAT
1519+
" is reporting a reduced length of %d - use GetStringUTFLengthAsLong instead",
1520+
full_length, result);
1521+
NativeReportJNIWarning(thr, ss.as_string());
1522+
}
1523+
functionExit(thr);
1524+
return result;
1525+
JNI_END
1526+
1527+
JNI_ENTRY_CHECKED(jlong,
1528+
checked_jni_GetStringUTFLengthAsLong(JNIEnv *env,
1529+
jstring str))
1530+
functionEnter(thr);
1531+
IN_VM(
1532+
checkString(thr, str);
1533+
)
1534+
jlong result = UNCHECKED()->GetStringUTFLengthAsLong(env,str);
15141535
functionExit(thr);
15151536
return result;
15161537
JNI_END
@@ -2283,7 +2304,12 @@ struct JNINativeInterface_ checked_jni_NativeInterface = {
22832304

22842305
// Virtual threads
22852306

2286-
checked_jni_IsVirtualThread
2307+
checked_jni_IsVirtualThread,
2308+
2309+
// Large UTF8 support
2310+
2311+
checked_jni_GetStringUTFLengthAsLong
2312+
22872313
};
22882314

22892315

src/hotspot/share/runtime/threads.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,7 @@ jboolean Threads::is_supported_jni_version(jint version) {
984984
if (version == JNI_VERSION_19) return JNI_TRUE;
985985
if (version == JNI_VERSION_20) return JNI_TRUE;
986986
if (version == JNI_VERSION_21) return JNI_TRUE;
987+
if (version == JNI_VERSION_24) return JNI_TRUE;
987988
return JNI_FALSE;
988989
}
989990

src/hotspot/share/utilities/dtrace_disabled.hpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2024, 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
@@ -783,6 +783,10 @@
783783
#define HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY_ENABLED() 0
784784
#define HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(arg0)
785785
#define HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN_ENABLED() 0
786+
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY(arg0, arg1)
787+
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_ENTRY_ENABLED() 0
788+
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN(arg0)
789+
#define HOTSPOT_JNI_GETSTRINGUTFLENGTHASLONG_RETURN_ENABLED() 0
786790
#define HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY(arg0, arg1, arg2, arg3, arg4)
787791
#define HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY_ENABLED() 0
788792
#define HOTSPOT_JNI_GETSTRINGUTFREGION_RETURN()

src/java.base/share/native/include/jni.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1996, 2024, 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
@@ -775,6 +775,12 @@ struct JNINativeInterface_ {
775775

776776
jboolean (JNICALL *IsVirtualThread)
777777
(JNIEnv* env, jobject obj);
778+
779+
/* Large UTF8 Support */
780+
781+
jlong (JNICALL *GetStringUTFLengthAsLong)
782+
(JNIEnv *env, jstring str);
783+
778784
};
779785

780786
/*
@@ -1623,6 +1629,9 @@ struct JNIEnv_ {
16231629
jsize GetStringUTFLength(jstring str) {
16241630
return functions->GetStringUTFLength(this,str);
16251631
}
1632+
jlong GetStringUTFLengthAsLong(jstring str) {
1633+
return functions->GetStringUTFLengthAsLong(this,str);
1634+
}
16261635
const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
16271636
return functions->GetStringUTFChars(this,str,isCopy);
16281637
}
@@ -1993,6 +2002,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved);
19932002
#define JNI_VERSION_19 0x00130000
19942003
#define JNI_VERSION_20 0x00140000
19952004
#define JNI_VERSION_21 0x00150000
2005+
#define JNI_VERSION_24 0x00180000
19962006

19972007
#ifdef __cplusplus
19982008
} /* extern "C" */

test/hotspot/jtreg/native_sanity/JniVersion.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2024, 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
@@ -27,12 +27,12 @@
2727
*/
2828
public class JniVersion {
2929

30-
public static final int JNI_VERSION_21 = 0x00150000;
30+
public static final int JNI_VERSION_24 = 0x00180000;
3131

3232
public static void main(String... args) throws Exception {
3333
System.loadLibrary("JniVersion");
3434
int res = getJniVersion();
35-
if (res != JNI_VERSION_21) {
35+
if (res != JNI_VERSION_24) {
3636
throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res));
3737
}
3838
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
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+
/* @test
25+
* @bug 8328877
26+
* @summary Test warning for GetStringUTFLength and functionality of GetStringUTFLengthAsLong
27+
* @requires vm.bits == 64
28+
* @library /test/lib
29+
* @modules java.management
30+
* @run main/native TestLargeUTF8Length launch
31+
*/
32+
33+
import java.util.Arrays;
34+
import jdk.test.lib.Utils;
35+
import jdk.test.lib.process.ProcessTools;
36+
import jdk.test.lib.process.OutputAnalyzer;
37+
38+
public class TestLargeUTF8Length {
39+
40+
static {
41+
System.loadLibrary("TestLargeUTF8Length");
42+
}
43+
44+
static native void checkUTF8Length(String s, long utf8Length);
45+
46+
static void test() {
47+
int length = Integer.MAX_VALUE/2 + 1;
48+
char character = (char)0XD1; // N with tilde
49+
long utf8Length = 2L * length;
50+
char[] chrs = new char[length];
51+
Arrays.fill(chrs, character);
52+
String s = new String(chrs);
53+
checkUTF8Length(s, utf8Length);
54+
}
55+
56+
public static void main(String[] args) throws Throwable {
57+
if (args == null || args.length == 0) {
58+
test();
59+
return;
60+
}
61+
62+
OutputAnalyzer oa = ProcessTools.executeTestJava("-Xms9G",
63+
"-Xmx9G",
64+
"-Xcheck:jni",
65+
"-Djava.library.path=" + Utils.TEST_NATIVE_PATH,
66+
"TestLargeUTF8Length");
67+
String warning = "WARNING: large String with modified UTF-8 length .*" +
68+
"is reporting a reduced length of .* - use GetStringUTFLengthAsLong instead";
69+
oa.shouldHaveExitValue(0);
70+
oa.stdoutShouldMatch(warning);
71+
oa.reportDiagnosticSummary();
72+
}
73+
}

0 commit comments

Comments
 (0)