Before patch:
1st attempt [ForkJoinPool.commonPool-worker-3]:
java.lang.ExceptionInInitializerError
at ClinitFailure.lambda$main$0(ClinitFailure.java:20)
at
java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at
java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1728)
at
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.RuntimeException: Can't get it!
at ClinitFailure$Faulty.<clinit>(ClinitFailure.java:12)
... 8 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of
bounds for length 0
at ClinitFailure$Faulty.<clinit>(ClinitFailure.java:10)
... 8 more
2nd attempt [ForkJoinPool.commonPool-worker-5]:
java.lang.NoClassDefFoundError: Could not initialize class
ClinitFailure$Faulty
at ClinitFailure.lambda$main$1(ClinitFailure.java:28)
at
java.base/java.util.concurrent.CompletableFuture$UniRun.tryFire(CompletableFuture.java:783)
at
java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:479)
at
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
After patch:
1st attempt [ForkJoinPool.commonPool-worker-3]:
java.lang.ExceptionInInitializerError
at ClinitFailure.lambda$main$0(ClinitFailure.java:18)
at
java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at
java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1728)
at
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.RuntimeException: Can't get it!
at ClinitFailure$Faulty.<clinit>(ClinitFailure.java:10)
... 8 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of
bounds for length 0
at ClinitFailure$Faulty.<clinit>(ClinitFailure.java:8)
... 8 more
2nd attempt [ForkJoinPool.commonPool-worker-5]:
java.lang.NoClassDefFoundError: Could not initialize class
ClinitFailure$Faulty
at
java.base/java.lang.ClassLoader.throwReinitException(ClassLoader.java:3062)
at ClinitFailure.lambda$main$1(ClinitFailure.java:25)
at
java.base/java.util.concurrent.CompletableFuture$UniRun.tryFire(CompletableFuture.java:783)
at
java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:479)
at
java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at
java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at
java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at
java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.ExceptionInInitializerError: 11 ms ago in
thread ForkJoinPool.commonPool-worker-3
at ClinitFailure.lambda$main$0(ClinitFailure.java:18)
at
java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at
java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1728)
... 5 more
Caused by: java.lang.RuntimeException: Can't get it!
at ClinitFailure$Faulty.<clinit>(ClinitFailure.java:10)
... 8 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of
bounds for length 0
at ClinitFailure$Faulty.<clinit>(ClinitFailure.java:8)
... 8 more
This is what gets printed by the sample program:
public class ClinitFailure {
static class Faulty {
static {
try {
int i = (new int[0])[1];
} catch (Exception e) {
throw new RuntimeException("Can't get it!", e);
}
}
}
public static void main(String[] args) throws Exception {
CompletableFuture.runAsync(() -> {
try {
new Faulty();
} catch (Throwable e) {
System.out.printf("\n1st attempt [%s]:\n\n",
Thread.currentThread().getName());
e.printStackTrace(System.out);
}
}).thenRunAsync(() -> {
try {
new Faulty();
} catch (Throwable e) {
System.out.printf("\n2nd attempt [%s]:\n\n",
Thread.currentThread().getName());
e.printStackTrace(System.out);
}
}).join();
}
}
When the following patch is applied:
http://cr.openjdk.java.net/~plevart/jdk-dev/8203826_NoClassDefFoundError.cause/webrev.01/
I took Volker's patch and modified it a bit:
- The logic to construct and throw NoClassDefFoundError and to
record initial <clinit> exception is in java now. It uses
ClassLoaderValue internal API to save the chains of exception(s)
for faulty classes. It is easier to do such logic in Java and less
error prone.
- The chain of original <clinit> exception(s) is replaced with
substitutes that mimic .toString() and .printStackTrace() methods
of original chain, but don't reference any classes outside
bootstrap class loader
- The replacement chain of original exceptions adds a custom
message insert into the top exception as a hint to the user:
java.lang.ExceptionInInitializerError: 11 ms ago in thread
ForkJoinPool.commonPool-worker-3
So, what do you think of this one?
Regards, Peter