JDK-8309034 : NoClassDefFoundError when initializing Long$LongCache
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 21
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2023-05-29
  • Updated: 2023-08-24
  • Resolved: 2023-06-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 22
22 b03Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
Please excuse for the messy fuzzy test (attached).

java.lang.NoClassDefFoundError: Could not initialize class java.lang.Long$LongCache
        at java.base/java.lang.Long.valueOf(Long.java:1202)
        at a.<init>(Test_545.java:10)
        at Test_545.j(Test_545.java:31)
        at Test_545.main(Test_545.java:24)

A repetition of the JDK-8048190? I can see no obvious reason to fail here. Or a clearly expressed one.
Comments
Changeset: 4c3efb39 Author: David Holmes <dholmes@openjdk.org> Date: 2023-06-20 21:58:31 +0000 URL: https://git.openjdk.org/jdk/commit/4c3efb39107829d0025bd23a5fa532767fa9b3a7
20-06-2023

We can do the same for OutOfMemoryError.
13-06-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/14438 Date: 2023-06-13 06:43:11 +0000
13-06-2023

Here's the output when we save a stackless preallocated SOE instance as the initialization failure reason: java.lang.NoClassDefFoundError: Could not initialize class java.lang.Long$LongCache at java.base/java.lang.Long.valueOf(Long.java:1202) at a.<init>(Test_545.java:10) at Test_545.j(Test_545.java:31) at Test_545.main(Test_545.java:24) Caused by: java.lang.StackOverflowError
09-06-2023

In JDK-8302491 we tried to make things more resilient in the StackOverflowError case. As noted there we can't just save and use the original SOE without potentially introducing other problems. However, it may be that we can have a pre-allocated, stackless SOE instance that could be thrown in lieu of the original exception.
05-06-2023

I will take another look at the way we try to handle clinit failures in the VM to see if there is anything else we can do. Unfortunately I think this is actually working as designed from the language perspective because while the try block should complete abruptly due to the SOE, the finally clause then completes abruptly due to the NCDFE and the SOE is lost. This seems like a case where it would have been good for the JLS to be updated when suppressed exceptions were introduced, as the exception from the finally clause suppresses the exception from the try block. But as I said I will look again to see if there is anything more we can do to try and get the original failure reason to stick to the NCDFE.
30-05-2023

The main reason for the exception is the stack overflow, so reporting a SOE to the user (be it the programmer or the code runner) would be the best. Reporting NCDFE is kind of misleading, but acceptable if that is backed up by its own reason (the SOE). Current behaviour I still consider an issue. Probably a minor one (due to contrived example, rarely to see in the wild), but this still is an issue.
30-05-2023

So creating an `a` creates a `d` which is-a `a` so we have infinite recursion and trigger a StackOverflowError. We then try to execute the finally clause which will also trigger SOE at some point. If that point is initialization of the LongCache, then creating the EIIE will also fail due to SOE and so we cannot save the original cause of the initialization failure and the class is simply marked as erroneous. Eventually the stack unwinds enough that the execution of the finally just sees that LongCache is erroneous and so throws NCDFE.
29-05-2023

> Your exception log seems truncated Fixed (a new version attached).
29-05-2023

I used Java 19 and 20 and got the StackOverflow I reported above. Your exception log seems truncated as we never get to the actual NCDFE.
29-05-2023

> Please add `-Xlog:exceptions=trace" Attached.
29-05-2023

To answer myself, yes it reproduces. The problem is a StackOverflow (well multiple ones) that prevent static iniialization from completing, but which also prevent the original EIIE from being created and thrown as well. If you boost the stack size then you can see the SOE happening after all the class initialization stuff is done.
29-05-2023

Does this reproduce easily? Please add `-Xlog:exceptions=trace" to see what happens to the original exception.
29-05-2023