jetty / jetty/jetty.project

Suppressed exceptions from Quiche static initializer are only given out during initial classloading

Open
#15,430 0 comments 0 reactions 0 assignees View on GitHub
Enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.