JDK-8291458 : Hotspot execute a correct test cases and report NoClassDefFoundError
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8,11,17,18,20
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2022-07-21
  • Updated: 2022-08-01
  • Resolved: 2022-07-28
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Microsoft Windows 10 Professional
10.0.19044 Build 19044
AMD Ryzen 5 5600G with Radeon Graphics 3.90 GHz
Memory 32 GB

openjdk version "1.8.0_332"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_332-b09)
OpenJDK 64-Bit Server VM (Temurin)(build 25.332-b09, mixed mode)

openjdk version "11.0.15" 2022-04-19
OpenJDK Runtime Environment Temurin-11.0.15+10 (build 11.0.15+10)
OpenJDK 64-Bit Server VM Temurin-11.0.15+10 (build 11.0.15+10, mixed mode)

A DESCRIPTION OF THE PROBLEM :
In test case testCase20, we tried to call testCase20_2's test_mula () method after catching Throwable var1, but hotspot will report the java.lang. NoClassDefFoundError that caused the application to terminate.

ACTUAL -
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class testCase20_2
        at testCase20.run(testCase20.java:15)
        at testCase20.main(testCase20.java:7)

---------- BEGIN SOURCE ----------

public class testCase20 {
    public testCase20() {
    }

    public static void main(String[] var0) {
        (new testCase20()).run();
    }

    public void run() {
        try {
            this.run();
        } catch (Throwable var1) {
            double[] var10001 = new double[2];
            testCase20_2.test_mula(var10001, var10001, var10001);
        }

    }
}
class testCase20_2 {
    public static int my_check_sum = 0;

    static {
        my_check_sum = check_sum.run(my_check_sum, my_check_sum);
    }

    public testCase20_2() {
    }

    public static void test_mula(double[] var0, double[] var1, double[] var2) {


    }
}
class check_sum {
    public check_sum() {
    }

    public static int run(int var0, int var1) {
        var0 += Integer.hashCode(var1);
        return Integer.hashCode(var0);
    }
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
Actually the lack of original exception information was fixed in JDK 18 by JDK-8048190. If you run under JDK 18+ then you will see: Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class testCase20_2 at testCase20.run(testCase20.java:14) at testCase20.main(testCase20.java:6) Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.StackOverflowError [in thread "main"] at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013) at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862) at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) at testCase20_2.<clinit>(testCase20.java:23) at testCase20.run(testCase20.java:14) at testCase20.run(testCase20.java:11) ... at testCase20.run(testCase20.java:11)
29-07-2022

Issue is reproduced. java.lang.NoClassDefFoundError exception is thrown at runtime. OS: Windows 10 JDK 8u341: Fail JDK 11.0.16:Fail JDK 17.0.4:Fail JDK 18.0.2:Fail JDK 20ea6:Fail Output: Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class testCase20_2 at testCase20.run(testCase20.java:14) at testCase20.main(testCase20.java:6) Moving it to dev team for further analysis.
28-07-2022

This is just a lack of understanding about what actually goes wrong with this program (and it reads like a programming homework assignment). The exact behaviour depends on the size of stack and how much stack is needed for the different parts - you can see the details by running with -Xlog:exceptions=trace. Here's the general scenario: The recursive call to this.run() will eventually trigger a StackOverflowError which will be caught and we try to execute the catch block. But we are out of stack and so throw a secondary StackOverflowError. That gets caught by the next run() up the stack and the process can repeat a few times. At some point we have enough stack to attempt to call test_mula, but to do that class testCase20_2 needs to be statically initialized so we execute the <clinit> and try to execute check_sum.run. But we again run out of stack space so this will throw yet another StackOverflowError. Because that happens during <clinit> the VM "catches" it and replaces it with an ExceptionInInitializerError and the class is marked as erroneous. Now the EIIE is thrown and we unwind from that call to run() and the EIIE is then caught by the prior call to run() and we start to execute the catch block. Again testCase20_2 needs to be initialized, but it has been marked as erroneous due to the <clinit> throwing StackOverflowError, and so the NoClassDefFoundError is thrown (as required by the specification). This repeats as the call stack unwinds until eventually the first call to run() throws the NoClassDefFoundError. There is no bug here. What is missing is any reporting of what initially caused the initialization error. There have been requests to provide that, but it is not quite as simple as it might seem - I'm not sure what the current status of that enhancement request is.
28-07-2022