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

Volker Simonis volker.simonis at gmail.com
Wed Jun 10 23:02:39 UTC 2015


On Wednesday, June 10, 2015, Mandy Chung <mandy.chung at oracle.com> wrote:

>
> > On Jun 10, 2015, at 9:23 AM, Volker Simonis <volker.simonis at gmail.com
> <javascript:;>> 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.
>
>
Sure, I'll do that.

Otherwise looks good.  No need to generate a webrev as long as you make the
> change before the push.
>
>
Thanks for the review!
Regards,
Volker


> > 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
> <javascript:;>> 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
> <javascript:;>> 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
> <javascript:;>> 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
> <javascript:;>>
> >>>>> 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 <javascript:;>>
> >>>>>>> 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 hotspot-dev mailing list