RFR(M): 8203824: Chain exception from initialization in later NoClassDefFoundErrors.

David Holmes david.holmes at oracle.com
Wed Jun 6 21:27:40 UTC 2018

Hi Goetz,

On 7/06/2018 1:17 AM, Lindenmaier, Goetz wrote:
> Hi Karen and David,
> just keeping a String concatenated into the message would be
> appealing simple.
> But the problem is that it is not easy to know which is the
> needed information.
> For example in the test, you get
> java.lang.NoClassDefFoundError: NoClassDefFoundErrorTest$ClassWithFailedInitializer: cannot initialize class because prior initialization attempt failed
> 	at NoClassDefFoundErrorTest.test_chainStaticInitializerException(NoClassDefFoundErrorTest.java:132)
> 	at NoClassDefFoundErrorTest.main(NoClassDefFoundErrorTest.java:149)
> 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
> 	at com.sun.javatest.regtest.agent.MainActionHelper$SameVMRunnable.run(MainActionHelper.java:229)
> 	at java.base/java.lang.Thread.run(Thread.java:832)
> Caused by: java.lang.ExceptionInInitializerError
> 	at NoClassDefFoundErrorTest.test_chainStaticInitializerException(NoClassDefFoundErrorTest.java:112)
> 	... 7 more
> Caused by: java.lang.NullPointerException
> 	at NoClassDefFoundErrorTest$ClassWithFailedInitializer.<clinit>(NoClassDefFoundErrorTest.java:100)
> 	... 8 more
> And it is the NullPointerException you want to see, that tells you the problem is at NoClassDefFoundErrorTest.java:100

It is not reasonable IMHO to expect to be able to diagnose the detailed 
cause of the original exception from the secondary NCDFE. That should be 
done from the original encounter with the exception and the 
ExceptionInInitializerError. I see the current request as being 
informational in nature not diagnostic.

If the original exception is being swallowed then logging can be used to 
track that.

Again I don't like to see a price being paid for diagnostic information 
that might never be asked for. YMMV.


> Best regards,
>    Goetz,.
>> -----Original Message-----
>> From: Karen Kinnear [mailto:karen.kinnear at oracle.com]
>> Sent: Mittwoch, 6. Juni 2018 15:19
>> To: David Holmes <david.holmes at oracle.com>
>> Cc: Lindenmaier, Goetz <goetz.lindenmaier at sap.com>; hotspot-runtime-
>> dev at openjdk.java.net
>> Subject: Re: RFR(M): 8203824: Chain exception from initialization in later
>> NoClassDefFoundErrors.
>> My mental model here is the original exception type and message should be
>> saved.
>> It is not clear to me the value in this particular case of a backtrace from the
>> clinit failure - I do not
>> see how that particular failure would be related to the calling context.
>> thanks,
>> Karen
>>> On Jun 5, 2018, at 10:07 PM, David Holmes <david.holmes at oracle.com>
>> wrote:
>>> Hi Goetz,
>>> On 5/06/2018 11:21 PM, Lindenmaier, Goetz wrote:
>>>> Hi David,
>>>> I also would prefer to keep this field within hotspot.
>>>> The reason we use a Java function is that that
>>>> also calls out to a routine that transforms the
>>>> backtrace to stackTrace recursively for the chained
>>>> exceptions, which was implemented in Java.
>>>> We did this to make sure we don't keep any classes
>>>> alive that are referenced by the backtrace.
>>>> I didn't include that (yet), because that calls back into
>>>> the VM ...
>>>> Do you think I should address this issue right away,
>>>> or do you think it's overly cautious to free the backtrace?
>>> Hadn't thought too much about this aspect - seems to open a bit of a can of
>> worms. The thread that originally hit the exception could be operating
>> entirely within a child loader of the defining loader of the class in question.
>> That child loader and all its classes could be unloaded by the time the next
>> thread tries to load the class and retrieve the original exception. So having
>> the backtrace keep those classes alive seems bad. Converting the backtrace
>> to strackTraceElements addresses that - but at the expense of a complicated
>> Java-level transformation.
>>> I'm very reluctant to add such complexities here. My basic position is that
>> whichever thread encountered the original ExceptionInInitializerError should
>> be reporting it some way, not silently swallowing it - so diagnosis of the
>> problem should be apparent from logs. With that in mind I would suggest
>> clearing the backtrace so we only report the type of exception and the
>> message - _but_ that doesn't work because the original exception may still
>> be inflight in the original thread that encountered it! So maybe the original
>> exception type and message should simply be added to the message for the
>>> Thanks,
>>> David
>>>> Best regards,
>>>>    Goetz.
>>>>> -----Original Message-----
>>>>> From: David Holmes [mailto:david.holmes at oracle.com]
>>>>> Sent: Dienstag, 5. Juni 2018 04:36
>>>>> To: Lindenmaier, Goetz <goetz.lindenmaier at sap.com>; hotspot-
>> runtime-
>>>>> dev at openjdk.java.net
>>>>> Subject: Re: RFR(M): 8203824: Chain exception from initialization in later
>>>>> NoClassDefFoundErrors.
>>>>> Hi Goetz,
>>>>> On 2/06/2018 2:02 AM, Lindenmaier, Goetz wrote:
>>>>>> Hi,
>>>>>> If static initialization of a class fails, an ExceptionInInitializerError
>>>>>> is thrown. Later accesses to this class will fail, too. They report
>>>>>> a NoClassDefFoundError. This is misleading, as the class has been
>>>>>> found in first place but the initialization failed.
>>>>>> To give more context, retain the previous ExceptionInInitializerError
>>>>>> and chain it into the NoClassDefFoundError:
>>>>>> I added a field to java/lang/Class to retain the exception.
>>>>>> This is the design we followed in SAP JVM. I am not sure whether
>>>>>> the additional memory consumption of Class is acceptable, or whether
>>>>>> a hash map holding the exceptions internally would be a better
>>>>>> design.
>>>>> I suggest moving the field to instanceKlass and keeping this entirely
>>>>> within the VM. I would not want to see the change on the Java side or
>>>>> the need for a Java upcall to set this - you might hit more exceptions
>>>>> in the process! Any change on the Java side has to go through the
>>>>> core-libs folk anyway.
>>>>> Thanks,
>>>>> David
>>>>> -----
>>>>>> I also left out code that transforms the Throwable::backtrace in the
>>>>> retained
>>>>>> ExceptionInInitializerError and it's recursively chained exceptions into
>>>>>> Throwable::stackTrace and limits the recursively chained exceptions.
>>>>>> If this change is appreciated, I'll add that in a later change.
>>>>>> I found a test for NoClassDefFoundError messages and extended that.
>>>>>> I moved the existing test into the canonical location under
>>>>> /exceptionMsgs/
>>>>>> Best regards,
>>>>>>     Goetz.
>>>>>> Failing class initialization throws a ExceptionInInitializerError.
>>>>>> Later accesses to this class throw a NoClassDefFoundErrors
>>>>>> hiding the original cause.
>>>>>> This change adds code to chain the initial EIIE in the NCDFE.
>>>>>> http://cr.openjdk.java.net/~goetz/wr18/8203826-exMsg-
>>>>> NoClassDefFoundError/webrev
>>>>>> The initial EIIE is stored in the Class that failed to initialize.
>>>>>> I thought

More information about the hotspot-runtime-dev mailing list