Skip to content

Commit b8453eb

Browse files
committed
8275007: Java fails to start with null charset if LC_ALL is set to certain locales
Reviewed-by: rriggs, iris, joehw, alanb
1 parent 231fb61 commit b8453eb

File tree

2 files changed

+61
-63
lines changed

2 files changed

+61
-63
lines changed

src/java.base/share/classes/java/lang/System.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import java.io.IOException;
3434
import java.io.InputStream;
3535
import java.io.PrintStream;
36-
import java.io.UnsupportedEncodingException;
3736
import java.lang.annotation.Annotation;
3837
import java.lang.invoke.MethodHandle;
3938
import java.lang.invoke.MethodType;
@@ -45,9 +44,9 @@
4544
import java.lang.reflect.Modifier;
4645
import java.net.URI;
4746
import java.net.URL;
48-
import java.nio.charset.CharacterCodingException;
4947
import java.nio.channels.Channel;
5048
import java.nio.channels.spi.SelectorProvider;
49+
import java.nio.charset.CharacterCodingException;
5150
import java.nio.charset.Charset;
5251
import java.security.AccessControlContext;
5352
import java.security.AccessController;
@@ -84,6 +83,7 @@
8483
import sun.nio.fs.DefaultFileSystemProvider;
8584
import sun.reflect.annotation.AnnotationType;
8685
import sun.nio.ch.Interruptible;
86+
import sun.nio.cs.UTF_8;
8787
import sun.security.util.SecurityConstants;
8888

8989
/**
@@ -188,6 +188,11 @@ private System() {
188188
@SuppressWarnings("removal")
189189
private static volatile SecurityManager security; // read by VM
190190

191+
// `sun.jnu.encoding` if it is not supported. Otherwise null.
192+
// It is initialized in `initPhase1()` before any charset providers
193+
// are initialized.
194+
private static String notSupportedJnuEncoding;
195+
191196
// return true if a security manager is allowed
192197
private static boolean allowSecurityManager() {
193198
return (allowSecurityManager != NEVER);
@@ -2017,10 +2022,9 @@ public static void loadLibrary(String libname) {
20172022
* Create PrintStream for stdout/err based on encoding.
20182023
*/
20192024
private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
2020-
if (enc != null) {
2021-
try {
2022-
return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
2023-
} catch (UnsupportedEncodingException uee) {}
2025+
if (enc != null) {
2026+
return new PrintStream(new BufferedOutputStream(fos, 128), true,
2027+
Charset.forName(enc, UTF_8.INSTANCE));
20242028
}
20252029
return new PrintStream(new BufferedOutputStream(fos, 128), true);
20262030
}
@@ -2113,6 +2117,13 @@ private static void initPhase1() {
21132117
VM.saveProperties(tempProps);
21142118
props = createProperties(tempProps);
21152119

2120+
// Check if sun.jnu.encoding is supported. If not, replace it with UTF-8.
2121+
var jnuEncoding = props.getProperty("sun.jnu.encoding");
2122+
if (jnuEncoding == null || !Charset.isSupported(jnuEncoding)) {
2123+
notSupportedJnuEncoding = jnuEncoding == null ? "null" : jnuEncoding;
2124+
props.setProperty("sun.jnu.encoding", "UTF-8");
2125+
}
2126+
21162127
StaticProperty.javaHome(); // Load StaticProperty to cache the property values
21172128

21182129
lineSeparator = props.getProperty("line.separator");
@@ -2141,7 +2152,6 @@ private static void initPhase1() {
21412152
Thread current = Thread.currentThread();
21422153
current.getThreadGroup().add(current);
21432154

2144-
21452155
// Subsystems that are invoked during initialization can invoke
21462156
// VM.isBooted() in order to avoid doing things that should
21472157
// wait until the VM is fully initialized. The initialization level
@@ -2248,6 +2258,14 @@ private static void initPhase3() {
22482258
WARNING: The Security Manager is deprecated and will be removed in a future release""");
22492259
}
22502260

2261+
// Emit a warning if `sun.jnu.encoding` is not supported.
2262+
if (notSupportedJnuEncoding != null) {
2263+
System.err.println(
2264+
"WARNING: The encoding of the underlying platform's" +
2265+
" file system is not supported: " +
2266+
notSupportedJnuEncoding);
2267+
}
2268+
22512269
initialErrStream = System.err;
22522270

22532271
// initializing the system class loader

src/java.base/share/native/libjava/jni_util.c

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -639,21 +639,6 @@ static jmethodID String_getBytes_ID; /* String.getBytes(enc) */
639639
static jfieldID String_coder_ID; /* String.coder */
640640
static jfieldID String_value_ID; /* String.value */
641641

642-
static jboolean isJNUEncodingSupported = JNI_FALSE;
643-
static jboolean jnuEncodingSupported(JNIEnv *env) {
644-
jboolean exe;
645-
if (isJNUEncodingSupported == JNI_TRUE) {
646-
return JNI_TRUE;
647-
}
648-
isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName (
649-
env, &exe,
650-
"java/nio/charset/Charset",
651-
"isSupported",
652-
"(Ljava/lang/String;)Z",
653-
jnuEncoding).z;
654-
return isJNUEncodingSupported;
655-
}
656-
657642
/* Create a new string by converting str to a heap-allocated byte array and
658643
* calling the appropriate String constructor.
659644
*/
@@ -671,22 +656,8 @@ newSizedStringJava(JNIEnv *env, const char *str, const int len)
671656
jclass strClazz = JNU_ClassString(env);
672657
CHECK_NULL_RETURN(strClazz, 0);
673658
(*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)str);
674-
if (jnuEncodingSupported(env)) {
675-
result = (*env)->NewObject(env, strClazz,
676-
String_init_ID, bytes, jnuEncoding);
677-
} else {
678-
/*If the encoding specified in sun.jnu.encoding is not endorsed
679-
by "Charset.isSupported" we have to fall back to use String(byte[])
680-
explicitly here without specifying the encoding name, in which the
681-
StringCoding class will pickup the iso-8859-1 as the fallback
682-
converter for us.
683-
*/
684-
jmethodID mid = (*env)->GetMethodID(env, strClazz,
685-
"<init>", "([B)V");
686-
if (mid != NULL) {
687-
result = (*env)->NewObject(env, strClazz, mid, bytes);
688-
}
689-
}
659+
result = (*env)->NewObject(env, strClazz,
660+
String_init_ID, bytes, jnuEncoding);
690661
(*env)->DeleteLocalRef(env, bytes);
691662
return result;
692663
}
@@ -766,11 +737,30 @@ InitializeEncoding(JNIEnv *env, const char *encname)
766737
strcmp(encname, "utf-16le") == 0) {
767738
fastEncoding = FAST_CP1252;
768739
} else {
740+
jboolean exe;
769741
jstring enc = (*env)->NewStringUTF(env, encname);
770742
if (enc == NULL)
771743
return;
772-
fastEncoding = NO_FAST_ENCODING;
773-
jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);
744+
745+
if ((jboolean) JNU_CallStaticMethodByName (
746+
env, &exe,
747+
"java/nio/charset/Charset",
748+
"isSupported",
749+
"(Ljava/lang/String;)Z",
750+
enc).z == JNI_TRUE) {
751+
fastEncoding = NO_FAST_ENCODING;
752+
jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc);
753+
} else {
754+
// jnuEncoding falls back to UTF-8
755+
jstring utf8 = (*env)->NewStringUTF(env, "UTF-8");
756+
if (utf8 == NULL) {
757+
(*env)->DeleteLocalRef(env, enc);
758+
return;
759+
}
760+
fastEncoding = FAST_UTF_8;
761+
jnuEncoding = (jstring)(*env)->NewGlobalRef(env, utf8);
762+
(*env)->DeleteLocalRef(env, utf8);
763+
}
774764
(*env)->DeleteLocalRef(env, enc);
775765
}
776766
} else {
@@ -822,32 +812,22 @@ static const char* getStringBytes(JNIEnv *env, jstring jstr) {
822812
if ((*env)->EnsureLocalCapacity(env, 2) < 0)
823813
return 0;
824814

825-
if (jnuEncodingSupported(env)) {
826-
hab = (*env)->CallObjectMethod(env, jstr, String_getBytes_ID, jnuEncoding);
827-
} else {
828-
jmethodID mid;
829-
jclass strClazz = JNU_ClassString(env);
830-
CHECK_NULL_RETURN(strClazz, 0);
831-
mid = (*env)->GetMethodID(env, strClazz,
832-
"getBytes", "()[B");
833-
if (mid != NULL) {
834-
hab = (*env)->CallObjectMethod(env, jstr, mid);
815+
hab = (*env)->CallObjectMethod(env, jstr, String_getBytes_ID, jnuEncoding);
816+
if (hab != 0) {
817+
if (!(*env)->ExceptionCheck(env)) {
818+
jint len = (*env)->GetArrayLength(env, hab);
819+
result = MALLOC_MIN4(len);
820+
if (result == 0) {
821+
JNU_ThrowOutOfMemoryError(env, 0);
822+
(*env)->DeleteLocalRef(env, hab);
823+
return 0;
824+
}
825+
(*env)->GetByteArrayRegion(env, hab, 0, len, (jbyte *)result);
826+
result[len] = 0; /* NULL-terminate */
835827
}
836-
}
837828

838-
if (!(*env)->ExceptionCheck(env)) {
839-
jint len = (*env)->GetArrayLength(env, hab);
840-
result = MALLOC_MIN4(len);
841-
if (result == 0) {
842-
JNU_ThrowOutOfMemoryError(env, 0);
843-
(*env)->DeleteLocalRef(env, hab);
844-
return 0;
845-
}
846-
(*env)->GetByteArrayRegion(env, hab, 0, len, (jbyte *)result);
847-
result[len] = 0; /* NULL-terminate */
829+
(*env)->DeleteLocalRef(env, hab);
848830
}
849-
850-
(*env)->DeleteLocalRef(env, hab);
851831
return result;
852832
}
853833

0 commit comments

Comments
 (0)