Suppressed exceptions from Quiche static initializer are only given out during initial classloading
- Dominant language
- Java
- Stars
- 4.1k
- Forks
- 2k
- Avg merge
- 3d 56m
- Merged PRs (30d)
- 48
Description
**Jetty version(s)**
12.1.11
**Enhancement Description**
The suppressed exceptions being thrown from https://github.com/jetty/jetty.project/blob/ce3c61a30e84425ae11772ab4f61aa2ee434d69d/jetty-core/jetty-quic/jetty-quic-quiche/jetty-quic-quiche-common/src/main/java/org/eclipse/jetty/quic/quiche/Quiche.java#L65 are only ever emitted during the initial class load. Subsequent references just lead to wrapping the `ExceptionInInitializerError` in a `NoClassDefFoundError` where the suppressed exceptions are not given out.
Example test:
```
public class QuicheTest {
@Test
void quicheBinding() {
SocketAddress address = new InetSocketAddress("localhost", 8080);
Quiche.toInetSocketAddress(address, false);
}
@Test
void quicheBinding2() {
SocketAddress address = new InetSocketAddress("localhost", 8080);
Quiche.toInetSocketAddress(address, false);
}
}
```
This leads to the following stack traces:
```
[ERROR] org.eclipse.aether.transport.jetty.QuicheTest.quicheBinding -- Time elapsed: 0.256 s <<< ERROR!
java.lang.ExceptionInInitializerError
at org.eclipse.aether.transport.jetty.QuicheTest.quicheBinding(QuicheTest.java:32)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.lang.IllegalStateException: no quiche binding implementation found
at org.eclipse.jetty.quic.quiche.Quiche.lambda$static$1(Quiche.java:64)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at org.eclipse.jetty.quic.quiche.Quiche.(Quiche.java:62)
... 4 more
Suppressed: java.lang.UnsatisfiedLinkError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /home/jenkins/.cache/JNA/temp/jna508570688502379720.tmp)
at com.sun.jna.Native.open(Native Method)
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:300)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:481)
at com.sun.jna.Library$Handler.(Library.java:197)
at com.sun.jna.Native.load(Native.java:618)
at org.eclipse.jetty.quic.quiche.jna.LibQuiche.(LibQuiche.java:39)
at org.eclipse.jetty.quic.quiche.jna.JnaQuicheBinding.initialize(JnaQuicheBinding.java:35)
at org.eclipse.jetty.quic.quiche.Quiche.lambda$static$0(Quiche.java:57)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:662)
at java.base/java.util.stream.ReferencePipeline.min(ReferencePipeline.java:703)
at org.eclipse.jetty.quic.quiche.Quiche.(Quiche.java:61)
... 4 more
[ERROR] org.eclipse.aether.transport.jetty.QuicheTest.quicheBinding2 -- Time elapsed: 0.005 s <<< ERROR!
java.lang.NoClassDefFoundError: Could not initialize class org.eclipse.jetty.quic.quiche.Quiche
at org.eclipse.aether.transport.jetty.QuicheTest.quicheBinding2(QuicheTest.java:38)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalStateException: no quiche binding implementation found [in thread "main"]
at org.eclipse.jetty.quic.quiche.Quiche.lambda$static$1(Quiche.java:64)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at org.eclipse.jetty.quic.quiche.Quiche.(Quiche.java:62)
at org.eclipse.aether.transport.jetty.QuicheTest.quicheBinding(QuicheTest.java:32)
... 3 more
```
The suppressed exception is notably missing from the second test method. Seems that the JRE (21 in my case) strips some information when emitting a `NoClassDefFoundError`. This is particularly nasty as the first usage/exception might be swallowed (see https://github.com/jetty/jetty.project/issues/15385).
Contributor guide
Research direction
Start with Quiche.java around the static initializer at lines 57-65 and reproduce the behavior using the two-call QuicheTest example. Add a regression test covering repeated references after initialization fails, then verify that the suppressed binding exception remains available on the later failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100