RFR(M): 8081674: EmptyStackException at startup if running with extended or unsupported charset

Mandy Chung mandy.chung at oracle.com
Wed Jun 10 19:02:35 UTC 2015


> On Jun 10, 2015, at 9:23 AM, Volker Simonis <volker.simonis at gmail.com> wrote:
> 
> Hy Mandy,
> 
> that's a real good proposal and it only requires changes in the jdk
> repository which makes it even more attractive.
> 
> I've just checked and it does indeed solve the initial
> EmptyStackException problem in both jdk8 and jdk9. Here are the
> corresponding webrevs:
> 
> http://cr.openjdk.java.net/~simonis/webrevs/2015/8081674.jdk8/

ClassLoader.java
   It should have done that.  Nit:
   Can you move line 1693 to 1868 closer to loadLibrary0 (the caller of findBuiltinLib)?
   Also make it private.

Same applies to jdk9.

Otherwise looks good.  No need to generate a webrev as long as you make the change before the push.

> http://cr.openjdk.java.net/~simonis/webrevs/2015/8081674.jdk9/
> 
> The only difference between 8 and 9 is the different location of the
> source files.
> Compared to your proposal I've only updated the copyright years where
> necessary and removed one comment in
> Java_java_lang_ClassLoader_findBuiltinLib() which seemed unnecessary
> to me now that findBuiltinLib() isn't located in NativeLibrary
> anymore.
> 

Thanks for taking it out.

> On jdk9 we are now running in another problem which is caused by the
> fact that the extended charsets are now being loaded by ServiceLoader
> (I've detailed that already in the bug report). But I think we can
> leave the fix of that problem to another change as this seems to
> require some more reasoning (see Alan's comments in the bug report).

Yes this is a harder problem that have to investigate further.

> 
> So are you OK now with pushing this change to jdk9 and requesting a
> downport to 8u-dev afterwards?
> 

Yes.  Approved.

Mandy

> Thank you and best regards,
> Volker
> 
> 
> On Wed, Jun 10, 2015 at 5:14 PM, Mandy Chung <mandy.chung at oracle.com> wrote:
>> Have you checked out this patch moving out findBuiltinLib from NativeLibrary class?
>>   http://cr.openjdk.java.net/~mchung/jdk9/webrevs/8081674/webrev.00/
>> 
>> Mandy
>> 
>>> On Jun 10, 2015, at 12:34 AM, Volker Simonis <volker.simonis at gmail.com> wrote:
>>> 
>>> Mandy, the example/stacktrace I sent was with 8u.
>>> 
>>> The problem isn't related to libzip, it is only the first library
>>> which gets loaded with System.loadLibrary().
>>> 
>>> The problem will occur with every library which gets loaded by
>>> System.loadLibrary() because
>>> java.lang.ClassLoader$NativeLibrary.findBuiltinLib() always calls
>>> jni_FindClass() if we're running on a unsupported locale.
>>> 
>>> On Tue, Jun 9, 2015 at 8:03 PM, Mandy Chung <mandy.chung at oracle.com> wrote:
>>>> Does my patch work fine on 8u?    If it works fine, I prefer to get that
>>>> simple fix in 8u and take the time to have a better fix in 9 (jdk9 is still
>>>> under development and I have assumed that it's not a show stopper to you.
>>>> Let me know if it blocks you).
>>>> 
>>>> A question to Sherman - do we have adequate tests to verify the move of
>>>> System.loadLibrary("zip") from system initialization to ZipFile
>>>> initialization for 8u?
>>>> 
>>>> Mandy
>>>> 
>>>> 
>>>> On 06/09/2015 10:09 AM, Volker Simonis wrote:
>>>>> 
>>>>> Hi Mandy,
>>>>> 
>>>>> thanks for looking into this.
>>>>> Uunfortunately your fix only helps to fix "java -version" :(
>>>>> 
>>>>> Running even a minimal HelloWorld will still fail with the following
>>>>> stack trace which is still caused by the same EmptyStackException:
>>>>> 
>>>>> Error: A JNI error has occurred, please check your installation and try
>>>>> again
>>>>> Exception in thread "main" java.lang.ExceptionInInitializerError
>>>>>    at sun.misc.Unsafe.ensureClassInitialized(Native Method)
>>>>>    at
>>>>> sun.misc.SharedSecrets.getJavaUtilZipFileAccess(SharedSecrets.java:158)
>>>>>    at sun.misc.URLClassPath$JarLoader.<clinit>(URLClassPath.java:765)
>>>>>    at sun.misc.URLClassPath$3.run(URLClassPath.java:530)
>>>>>    at sun.misc.URLClassPath$3.run(URLClassPath.java:520)
>>>>>    at java.security.AccessController.doPrivileged(Native Method)
>>>>>    at sun.misc.URLClassPath.getLoader(URLClassPath.java:519)
>>>>>    at sun.misc.URLClassPath.getLoader(URLClassPath.java:492)
>>>>>    at sun.misc.URLClassPath.getNextLoader(URLClassPath.java:457)
>>>>>    at sun.misc.URLClassPath.access$100(URLClassPath.java:64)
>>>>>    at sun.misc.URLClassPath$1.next(URLClassPath.java:239)
>>>>>    at sun.misc.URLClassPath$1.hasMoreElements(URLClassPath.java:250)
>>>>>    at java.net.URLClassLoader$3$1.run(URLClassLoader.java:601)
>>>>>    at java.net.URLClassLoader$3$1.run(URLClassLoader.java:599)
>>>>>    at java.security.AccessController.doPrivileged(Native Method)
>>>>>    at java.net.URLClassLoader$3.next(URLClassLoader.java:598)
>>>>>    at java.net.URLClassLoader$3.hasMoreElements(URLClassLoader.java:623)
>>>>>    at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
>>>>>    at
>>>>> sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
>>>>>    at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
>>>>>    at
>>>>> sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
>>>>>    at
>>>>> java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:354)
>>>>>    at
>>>>> java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393)
>>>>>    at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474)
>>>>>    at java.nio.charset.Charset$1.getNext(Charset.java:350)
>>>>>    at java.nio.charset.Charset$1.hasNext(Charset.java:365)
>>>>>    at java.nio.charset.Charset$2.run(Charset.java:410)
>>>>>    at java.nio.charset.Charset$2.run(Charset.java:407)
>>>>>    at java.security.AccessController.doPrivileged(Native Method)
>>>>>    at java.nio.charset.Charset.lookupViaProviders(Charset.java:406)
>>>>>    at java.nio.charset.Charset.lookup2(Charset.java:477)
>>>>>    at java.nio.charset.Charset.lookup(Charset.java:464)
>>>>>    at java.nio.charset.Charset.isSupported(Charset.java:505)
>>>>>    at
>>>>> sun.launcher.LauncherHelper.makePlatformString(LauncherHelper.java:580)
>>>>> Caused by: java.util.EmptyStackException
>>>>>    at java.util.Stack.peek(Stack.java:102)
>>>>>    at
>>>>> java.lang.ClassLoader$NativeLibrary.getFromClass(ClassLoader.java:1759)
>>>>>    at java.lang.ClassLoader$NativeLibrary.findBuiltinLib(Native Method)
>>>>>    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1870)
>>>>>    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1843)
>>>>>    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
>>>>>    at java.lang.System.loadLibrary(System.java:1122)
>>>>>    at java.util.zip.ZipFile.<clinit>(ZipFile.java:86)
>>>>>    ... 34 more
>>>>> 
>>>>> It's obvious that the way jni_FindClass is looking for the class
>>>>> context by calling the NativeLibrary::getFromClass method is hacky but
>>>>> I think that the proposed fix is the quite simple and non-intrusive.
>>>>> And we probably don't want a complete rework of this code for 8
>>>>> anyway. So why not fix it the proposed way in 8 and 9 for now? That
>>>>> will still leave us time to come up with a better clean-up at least
>>>>> for 9.
>>>>> 
>>>>> What do you think?
>>>>> 
>>>>> Regards,
>>>>> Volker
>>>>> 
>>>>> On Tue, Jun 9, 2015 at 1:35 AM, Mandy Chung <mandy.chung at oracle.com>
>>>>> wrote:
>>>>>> 
>>>>>> Hi Volker,
>>>>>> 
>>>>>> Your patch reminds me the question I have about loading zip library.
>>>>>> 
>>>>>> In JDK 9 (and earlier release), zip library is loaded by the VM during
>>>>>> startup (see ClassLoader::load_zip_library).  I think loadLibrary("zip")
>>>>>> is
>>>>>> no longer needed to be called from System::initializeSystemClass method
>>>>>> and
>>>>>> instead it can be loaded by java.util.zip.ZipFile static initializer.
>>>>>> 
>>>>>> Do you mind to try the patch (below)?  That may be a simpler fix.
>>>>>> 
>>>>>> I never like the way jni_FindClass to look for the class context by
>>>>>> calling
>>>>>> the NativeLibrary::getFromClass method.  I will have to look deeper other
>>>>>> alternative to clean that up.  If taking out loadLibrary("zip") resolves
>>>>>> your issue, this will give us time to come up with a better clean-up in
>>>>>> the
>>>>>> future.
>>>>>> 
>>>>>> Mandy
>>>>>> [1] https://bugs.openjdk.java.net/browse/JDK-4429040
>>>>>> 
>>>>>> diff --git a/src/share/classes/java/lang/System.java
>>>>>> b/src/share/classes/java/lang/System.java
>>>>>> --- a/src/share/classes/java/lang/System.java
>>>>>> +++ b/src/share/classes/java/lang/System.java
>>>>>> @@ -1192,10 +1192,6 @@
>>>>>>         setOut0(newPrintStream(fdOut,
>>>>>> props.getProperty("sun.stdout.encoding")));
>>>>>>         setErr0(newPrintStream(fdErr,
>>>>>> props.getProperty("sun.stderr.encoding")));
>>>>>> 
>>>>>> -        // Load the zip library now in order to keep
>>>>>> java.util.zip.ZipFile
>>>>>> -        // from trying to use itself to load this library later.
>>>>>> -        loadLibrary("zip");
>>>>>> -
>>>>>>         // Setup Java signal handlers for HUP, TERM, and INT (where
>>>>>> available).
>>>>>>         Terminator.setup();
>>>>>> 
>>>>>> diff --git a/src/share/classes/java/util/zip/ZipFile.java
>>>>>> b/src/share/classes/java/util/zip/ZipFile.java
>>>>>> --- a/src/share/classes/java/util/zip/ZipFile.java
>>>>>> +++ b/src/share/classes/java/util/zip/ZipFile.java
>>>>>> @@ -83,6 +83,7 @@
>>>>>> 
>>>>>>     static {
>>>>>>         /* Zip library is loaded from System.initializeSystemClass */
>>>>>> +        System.loadLibrary("zip");
>>>>>>         initIDs();
>>>>>> 
>>>>>>     }
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> On 06/08/2015 07:23 AM, Volker Simonis wrote:
>>>>>>> 
>>>>>>> Hi,
>>>>>>> 
>>>>>>> can I please get a review at least for the part of this fix which is
>>>>>>> common for jdk8 and jdk9. It's only a few lines in
>>>>>>> src/share/vm/prims/jni.cpp for the hotspot repository and one line
>>>>>>> src/java.base/share/classes/java/lang/ClassLoader.java for the jdk
>>>>>>> repository.
>>>>>>> 
>>>>>>> Thanks,
>>>>>>> Volker
>>>>>>> 
>>>>>>> 
>>>>>>> On Tue, Jun 2, 2015 at 6:12 PM, Volker Simonis
>>>>>>> <volker.simonis at gmail.com>
>>>>>>> wrote:
>>>>>>>> 
>>>>>>>> Hi,
>>>>>>>> 
>>>>>>>> can I please have review (and a sponsor) for these changes:
>>>>>>>> 
>>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8081674
>>>>>>>> http://cr.openjdk.java.net/~simonis/webrevs/2015/8081674.jdk
>>>>>>>> http://cr.openjdk.java.net/~simonis/webrevs/2015/8081674.hs
>>>>>>>> 
>>>>>>>> Please notice that the fix requires synchronous changes in the jdk and
>>>>>>>> the
>>>>>>>> hotspot forest.
>>>>>>>> 
>>>>>>>> The changes themselves are by far not that big as this explanation but
>>>>>>>> I
>>>>>>>> found the problem to be quite intricate so I tried to explain it as
>>>>>>>> good
>>>>>>>> as
>>>>>>>> I could. I'd suggest to read the HTML-formatted explanation in the
>>>>>>>> webrev
>>>>>>>> although the content is equal to the one in this mail:
>>>>>>>> 
>>>>>>>> Using an unsupported character encoding (e.g. vi_VN.TCVN on Linux)
>>>>>>>> results
>>>>>>>> in an immediate VM failure with jdk 8 and 9:
>>>>>>>> 
>>>>>>>> export LANG=vi_VN.TCVN
>>>>>>>> java -version
>>>>>>>> Error occurred during initialization of VM
>>>>>>>> java.util.EmptyStackException
>>>>>>>>        at java.util.Stack.peek(Stack.java:102)
>>>>>>>>        at
>>>>>>>> java.lang.ClassLoader$NativeLibrary.getFromClass(ClassLoader.java:1751)
>>>>>>>>        at java.lang.ClassLoader$NativeLibrary.findBuiltinLib(Native
>>>>>>>> Method)
>>>>>>>>        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1862)
>>>>>>>>        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1835)
>>>>>>>>        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
>>>>>>>>        at java.lang.System.loadLibrary(System.java:1119)
>>>>>>>>        at java.lang.System.initializeSystemClass(System.java:1194)
>>>>>>>> 
>>>>>>>> This is a consequence of "8005716: Enhance JNI specification to allow
>>>>>>>> support of static JNI libraries in Embedded JREs".
>>>>>>>> 
>>>>>>>> With jdk 9 we get this error even if we're running with a supported
>>>>>>>> charset
>>>>>>>> which is in the ExtendedCharsets (as opposed to being in the
>>>>>>>> StandardCharsets) class which is a consequence of delegating the
>>>>>>>> loading
>>>>>>>> of
>>>>>>>> the ExtendedCharsets class to the ServiceLoader in jdk 9.
>>>>>>>> 
>>>>>>>> export LANG=eo.iso-8859-3
>>>>>>>> output-jdk9/images/jdk/bin/java -version
>>>>>>>> Error occurred during initialization of VM
>>>>>>>> java.util.EmptyStackException
>>>>>>>>        at java.util.Stack.peek(Stack.java:102)
>>>>>>>>        at
>>>>>>>> java.lang.ClassLoader$NativeLibrary.getFromClass(ClassLoader.java:1737)
>>>>>>>>        at java.lang.ClassLoader$NativeLibrary.findBuiltinLib(Native
>>>>>>>> Method)
>>>>>>>>        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1866)
>>>>>>>>        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1840)
>>>>>>>>        at java.lang.Runtime.loadLibrary0(Runtime.java:874)
>>>>>>>>        at java.lang.System.loadLibrary(System.java:1111)
>>>>>>>>        at java.lang.System.initializeSystemClass(System.java:1186)
>>>>>>>> 
>>>>>>>> Here's why the exception happens for an unsupported charset (see the
>>>>>>>> mixed
>>>>>>>> stack trace below for the full details):
>>>>>>>> 
>>>>>>>> java.lang.System.loadLibrary() wants to load libzip.so. It calls
>>>>>>>> java.lang.Runtime.loadLibrary0() which at the very beginning calls the
>>>>>>>> native method ClassLoader$NativeLibrary.findBuiltinLib() which checks
>>>>>>>> if
>>>>>>>> the
>>>>>>>> corresponding library is already statically linked into the VM
>>>>>>>> (introduced
>>>>>>>> by 8005716).
>>>>>>>> Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib(),
>>>>>>>> the native implementation of findBuiltinLib() in Classloader.c calls
>>>>>>>> GetStringPlatformChars() to convert the library name into the native
>>>>>>>> platform encoding. GetStringPlatformChars() calls the helper function
>>>>>>>> jnuEncodingSupported() to check if the platform encoding which is
>>>>>>>> stored
>>>>>>>> in
>>>>>>>> the property "sun.jnu.encoding" is supported by Java.
>>>>>>>> jnuEncodingSupported()
>>>>>>>> is implemented as follows:
>>>>>>>> 
>>>>>>>> static jboolean isJNUEncodingSupported = JNI_FALSE;
>>>>>>>> static jboolean jnuEncodingSupported(JNIEnv *env) {
>>>>>>>>     jboolean exe;
>>>>>>>>     if (isJNUEncodingSupported == JNI_TRUE) {
>>>>>>>>         return JNI_TRUE;
>>>>>>>>     }
>>>>>>>>     isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName (
>>>>>>>>                                     env, &exe,
>>>>>>>>                                     "java/nio/charset/Charset",
>>>>>>>>                                     "isSupported",
>>>>>>>>                                     "(Ljava/lang/String;)Z",
>>>>>>>>                                     jnuEncoding).z;
>>>>>>>>     return isJNUEncodingSupported;
>>>>>>>> }
>>>>>>>> 
>>>>>>>> Once the function finds that the platform encoding is supported (by
>>>>>>>> calling
>>>>>>>> java.nio.charset.Charset.isSupported()) it caches this value and always
>>>>>>>> returns it on following calls. However if the platform encoding is not
>>>>>>>> supported, it ALWAYS calls java.nio.charset.Charset.isSupported() an
>>>>>>>> every
>>>>>>>> subsequent invocation.
>>>>>>>> 
>>>>>>>> In order to call the Java method Charset.isSupported() (in
>>>>>>>> JNU_CallStaticMethodByName() in file jni_util.c), we have to call
>>>>>>>> jni_FindClass() to convert the symbolic class name
>>>>>>>> "java.nio.charset.Charset" into a class reference.
>>>>>>>> 
>>>>>>>> But unfortunately, jni_FindClass() (from jni.cpp in libjvm.so) has a
>>>>>>>> special
>>>>>>>> handling if called from java.lang.ClassLoader$NativeLibrary to ensure
>>>>>>>> that
>>>>>>>> JNI_OnLoad/JNI_OnUnload are executed in the correct class context:
>>>>>>>> 
>>>>>>>>   instanceKlassHandle k (THREAD,
>>>>>>>> thread->security_get_caller_class(0));
>>>>>>>>   if (k.not_null()) {
>>>>>>>>     loader = Handle(THREAD, k->class_loader());
>>>>>>>>     // Special handling to make sure JNI_OnLoad and JNI_OnUnload are
>>>>>>>> executed
>>>>>>>>     // in the correct class context.
>>>>>>>>     if (loader.is_null() &&
>>>>>>>>         k->name() ==
>>>>>>>> vmSymbols::java_lang_ClassLoader_NativeLibrary()) {
>>>>>>>>       JavaValue result(T_OBJECT);
>>>>>>>>       JavaCalls::call_static(&result, k,
>>>>>>>>                                       vmSymbols::getFromClass_name(),
>>>>>>>> 
>>>>>>>> vmSymbols::void_class_signature(),
>>>>>>>>                                       thread);
>>>>>>>>       if (HAS_PENDING_EXCEPTION) {
>>>>>>>>         Handle ex(thread, thread->pending_exception());
>>>>>>>>         CLEAR_PENDING_EXCEPTION;
>>>>>>>>         THROW_HANDLE_0(ex);
>>>>>>>>       }
>>>>>>>> 
>>>>>>>> So if that's the case and jni_FindClass() was reallycalled from
>>>>>>>> ClassLoader$NativeLibrary, then jni_FindClass() calles
>>>>>>>> ClassLoader$NativeLibrary().getFromClass() to find out the
>>>>>>>> corresponding
>>>>>>>> context class which is supposed to be saved there in a field of type
>>>>>>>> java.util.Stack named "nativeLibraryContext":
>>>>>>>> 
>>>>>>>> // Invoked in the VM to determine the context class in
>>>>>>>> // JNI_Load/JNI_Unload
>>>>>>>> static Class<?> getFromClass() {
>>>>>>>>     return ClassLoader.nativeLibraryContext.peek().fromClass;
>>>>>>>> }
>>>>>>>> 
>>>>>>>> Unfortunately, "nativeLibraryContext" doesn't contain any entry at this
>>>>>>>> point and the invocation of Stack.peek() will throw the exception shown
>>>>>>>> before. In general, the "nativeLibraryContext" stack will be filled
>>>>>>>> later
>>>>>>>> on
>>>>>>>> in Runtime.loadLibrary0() like this:
>>>>>>>> 
>>>>>>>> NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin);
>>>>>>>> nativeLibraryContext.push(lib);
>>>>>>>> try {
>>>>>>>>     lib.load(name, isBuiltin);
>>>>>>>> } finally {
>>>>>>>>     nativeLibraryContext.pop();
>>>>>>>> }
>>>>>>>> 
>>>>>>>> such that it always contains at least one element later when
>>>>>>>> jni_FindClass()
>>>>>>>> will be invoked.
>>>>>>>> 
>>>>>>>> So in summary, the problem is that the implementors of 8005716 didn't
>>>>>>>> took
>>>>>>>> into account that calling ClassLoader$NativeLibrary.findBuiltinLib()
>>>>>>>> may
>>>>>>>> trigger a call to jni_FindClass() if we are running on a system with an
>>>>>>>> unsupported character encoding.
>>>>>>>> 
>>>>>>>> I'd suggest the following fix for this problem:
>>>>>>>> 
>>>>>>>> Change ClassLoader$NativeLibrary().getFromClass() to return null if the
>>>>>>>> stack is empty instead of throwing an exception:
>>>>>>>> 
>>>>>>>> static Class<?> getFromClass() {
>>>>>>>>     return ClassLoader.nativeLibraryContext.empty() ?
>>>>>>>>         null : ClassLoader.nativeLibraryContext.peek().fromClass;
>>>>>>>> }
>>>>>>>> 
>>>>>>>> Unfortunately this also requires a HotSpot change in jni_FindClass() in
>>>>>>>> order to properly handle the new 'null' return value:
>>>>>>>> 
>>>>>>>>   if (k.not_null()) {
>>>>>>>>     loader = Handle(THREAD, k->class_loader());
>>>>>>>>     // Special handling to make sure JNI_OnLoad and JNI_OnUnload are
>>>>>>>> executed
>>>>>>>>     // in the correct class context.
>>>>>>>>     if (loader.is_null() &&
>>>>>>>>         k->name() ==
>>>>>>>> vmSymbols::java_lang_ClassLoader_NativeLibrary()) {
>>>>>>>>       JavaValue result(T_OBJECT);
>>>>>>>>       JavaCalls::call_static(&result, k,
>>>>>>>>                                       vmSymbols::getFromClass_name(),
>>>>>>>> 
>>>>>>>> vmSymbols::void_class_signature(),
>>>>>>>>                                       thread);
>>>>>>>>       if (HAS_PENDING_EXCEPTION) {
>>>>>>>>         Handle ex(thread, thread->pending_exception());
>>>>>>>>         CLEAR_PENDING_EXCEPTION;
>>>>>>>>         THROW_HANDLE_0(ex);
>>>>>>>>       }
>>>>>>>>       oop mirror = (oop) result.get_jobject();
>>>>>>>>       if (oopDesc::is_null(mirror)) {
>>>>>>>>         loader = Handle(THREAD,
>>>>>>>> SystemDictionary::java_system_loader());
>>>>>>>>       } else {
>>>>>>>>         loader = Handle(THREAD,
>>>>>>>> 
>>>>>>>> 
>>>>>>>> InstanceKlass::cast(java_lang_Class::as_Klass(mirror))->class_loader());
>>>>>>>>         protection_domain = Handle(THREAD,
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> InstanceKlass::cast(java_lang_Class::as_Klass(mirror))->protection_domain());
>>>>>>>>       }
>>>>>>>>     }
>>>>>>>>   } else {
>>>>>>>>     // We call ClassLoader.getSystemClassLoader to obtain the system
>>>>>>>> class
>>>>>>>> loader.
>>>>>>>>     loader = Handle(THREAD, SystemDictionary::java_system_loader());
>>>>>>>>   }
>>>>>>>> 
>>>>>>>> These changes are sufficient to solve the problem in Java 8.
>>>>>>>> Unfortunately,
>>>>>>>> that's still not enough in Java 9 because there the loading of the
>>>>>>>> extended
>>>>>>>> charsets has been delegated to ServiceLoader. But ServiceLoader calls
>>>>>>>> ClassLoader.getBootstrapResources() which calls
>>>>>>>> sun.misc.Launcher.getBootstrapClassPath(). This leads to another
>>>>>>>> problem
>>>>>>>> during class initialization of sun.misc.Launcher if running on an
>>>>>>>> unsupported locale.
>>>>>>>> 
>>>>>>>> The first thing done in sun.misc.Launcher.<clinit> is the
>>>>>>>> initialisation
>>>>>>>> of
>>>>>>>> the bootstrap URLClassPath in the Launcher. However this initialisation
>>>>>>>> will
>>>>>>>> eventually call Charset.isSupported() and if we are running on an
>>>>>>>> unsupported locale this will inevitably end in another recursive call
>>>>>>>> to
>>>>>>>> ServiceLoader. But as explained below, ServiceLoader will query the
>>>>>>>> Launcher's bootstrap URLClassPath which will be still uninitialized at
>>>>>>>> that
>>>>>>>> point.
>>>>>>>> 
>>>>>>>> So we'll have to additionally guard guard against this situation on JDK
>>>>>>>> 9
>>>>>>>> like this:
>>>>>>>> 
>>>>>>>> private static Charset lookupExtendedCharset(String charsetName) {
>>>>>>>>     if (!sun.misc.VM.isBooted() ||             // see
>>>>>>>> lookupViaProviders()
>>>>>>>>         sun.misc.Launcher.getBootstrapClassPath() == null)
>>>>>>>>         return null;
>>>>>>>> 
>>>>>>>> This fixes the crashes, but still at the price of not having the
>>>>>>>> extended
>>>>>>>> charsets available during initialization until
>>>>>>>> Launcher.getBootstrapClassPath is set up properly. This may be still a
>>>>>>>> problem if the jdk is installed in a directory which contains
>>>>>>>> characters
>>>>>>>> specific to an extended encoding or if we have such characters in the
>>>>>>>> command line arguments.
>>>>>>>> 
>>>>>>>> Thank you and best regards,
>>>>>>>> Volker
>>>>>>>> 
>>>>>>>> 
>>>>>>>> Mixed stack trace of the initial EmptyStackException for unsupported
>>>>>>>> charsets described before:
>>>>>>>> 
>>>>>>>> Native frames: (J=compiled Java code, j=interpreted, Vv=VM code,
>>>>>>>> C=native
>>>>>>>> code)
>>>>>>>> j  java.util.Stack.peek()Ljava/lang/Object;+1
>>>>>>>> j
>>>>>>>> java.lang.ClassLoader$NativeLibrary.getFromClass()Ljava/lang/Class;+3
>>>>>>>> v  ~StubRoutines::call_stub
>>>>>>>> V  [libjvm.so+0x9d279a]  JavaCalls::call_helper(JavaValue*,
>>>>>>>> methodHandle*,
>>>>>>>> JavaCallArguments*, Thread*)+0x6b4
>>>>>>>> V  [libjvm.so+0xcad591]  os::os_exception_wrapper(void (*)(JavaValue*,
>>>>>>>> methodHandle*, JavaCallArguments*, Thread*), JavaValue*, methodHandle*,
>>>>>>>> JavaCallArguments*, Thread*)+0x45
>>>>>>>> V  [libjvm.so+0x9d20cf]  JavaCalls::call(JavaValue*, methodHandle,
>>>>>>>> JavaCallArguments*, Thread*)+0x8b
>>>>>>>> V  [libjvm.so+0x9d1d3b]  JavaCalls::call_static(JavaValue*,
>>>>>>>> KlassHandle,
>>>>>>>> Symbol*, Symbol*, JavaCallArguments*, Thread*)+0x139
>>>>>>>> V  [libjvm.so+0x9d1e3f]  JavaCalls::call_static(JavaValue*,
>>>>>>>> KlassHandle,
>>>>>>>> Symbol*, Symbol*, Thread*)+0x9d
>>>>>>>> V  [libjvm.so+0x9e6588]  jni_FindClass+0x428
>>>>>>>> C  [libjava.so+0x20208]  JNU_CallStaticMethodByName+0xff
>>>>>>>> C  [libjava.so+0x21cae]  jnuEncodingSupported+0x61
>>>>>>>> C  [libjava.so+0x22125]  JNU_GetStringPlatformChars+0x125
>>>>>>>> C  [libjava.so+0xedcd]
>>>>>>>> Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib+0x8b
>>>>>>>> j
>>>>>>>> 
>>>>>>>> 
>>>>>>>> java.lang.ClassLoader$NativeLibrary.findBuiltinLib(Ljava/lang/String;)Ljava/lang/String;+0
>>>>>>>> j
>>>>>>>> java.lang.ClassLoader.loadLibrary0(Ljava/lang/Class;Ljava/io/File;)Z+4
>>>>>>>> j
>>>>>>>> 
>>>>>>>> 
>>>>>>>> java.lang.ClassLoader.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)V+228
>>>>>>>> j
>>>>>>>> java.lang.Runtime.loadLibrary0(Ljava/lang/Class;Ljava/lang/String;)V+54
>>>>>>>> j  java.lang.System.loadLibrary(Ljava/lang/String;)V+7
>>>>>>>> j  java.lang.System.initializeSystemClass()V+113
>>>>>>>> v  ~StubRoutines::call_stub
>>>>>>>> V  [libjvm.so+0x9d279a]  JavaCalls::call_helper(JavaValue*,
>>>>>>>> methodHandle*,
>>>>>>>> JavaCallArguments*, Thread*)+0x6b4
>>>>>>>> V  [libjvm.so+0xcad591]  os::os_exception_wrapper(void (*)(JavaValue*,
>>>>>>>> methodHandle*, JavaCallArguments*, Thread*), JavaValue*, methodHandle*,
>>>>>>>> JavaCallArguments*, Thread*)+0x45
>>>>>>>> V  [libjvm.so+0x9d20cf]  JavaCalls::call(JavaValue*, methodHandle,
>>>>>>>> JavaCallArguments*, Thread*)+0x8b
>>>>>>>> V  [libjvm.so+0x9d1d3b]  JavaCalls::call_static(JavaValue*,
>>>>>>>> KlassHandle,
>>>>>>>> Symbol*, Symbol*, JavaCallArguments*, Thread*)+0x139
>>>>>>>> V  [libjvm.so+0x9d1e3f]  JavaCalls::call_static(JavaValue*,
>>>>>>>> KlassHandle,
>>>>>>>> Symbol*, Symbol*, Thread*)+0x9d
>>>>>>>> V  [libjvm.so+0xe3cceb]  call_initializeSystemClass(Thread*)+0xb0
>>>>>>>> V  [libjvm.so+0xe44444]
>>>>>>>> Threads::initialize_java_lang_classes(JavaThread*,
>>>>>>>> Thread*)+0x21a
>>>>>>>> V  [libjvm.so+0xe44b12]  Threads::create_vm(JavaVMInitArgs*,
>>>>>>>> bool*)+0x4a6
>>>>>>>> V  [libjvm.so+0xa19bd7]  JNI_CreateJavaVM+0xc7
>>>>>>>> C  [libjli.so+0xa520]  InitializeJVM+0x154
>>>>>>>> C  [libjli.so+0x8024]  JavaMain+0xcc
>>>>>>>> 
>>>>>>>> 
>>>> 
>> 




More information about the core-libs-dev mailing list