[GR-45893] jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE not available in native-image application #6457
Description
I am facing issues using jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE
in native images. The following code runs fine on a JVM, but fails in a native image:
AsynchronousSocketChannel socket = AsynchronousSocketChannel.open();
socket.setOption(jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE, 100);
Error in native-image:
Exception in thread "main" java.lang.UnsupportedOperationException: 'TCP_KEEPIDLE' not supported
at java.base@17.0.6/sun.nio.ch.AsynchronousSocketChannelImpl.setOption(AsynchronousSocketChannelImpl.java:461)
at com.example.repro.Application.main(Application.java:15)
The class jdk.net.ExtendedSocketOptions
registers some platform-dependent optionally available socket options. All of this is orchestrated by sun.net.ext.ExtendedSocketOptions
, which dynamically loads jdk.net.ExtendedSocketOptions
if available. jdk.net.ExtendedSocketOptions
then performs initialization of these additional options in a static code block.
For some reason, this static code block is not properly executed in the native-image. I know about build-time initialization of classes in native-images, but do not fully understand if this has an impact here.
To enable dynamic lookup of jdk.net.ExtendedSocketOptions
I also put the following information into a reflect-config.json
:
[
{
"name": "jdk.net.ExtendedSocketOptions"
}
]
Below I have provided a simple application to reproduce the issue. There I have provided additional debug output, which checks the conditions that check some boundary conditions for the exception to occur:
AsynchronousSocketChannel socket = AsynchronousSocketChannel.open();
Set<SocketOption<?>> options = socket.supportedOptions();
System.out.println("Has TCP_KEEPIDLE? " + options.contains(jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE));
System.out.println("Options: " + options);
Interestingly this produces the following output in a native-image:
Has TCP_KEEPIDLE? false
Options: [TCP_NODELAY, TCP_KEEPCOUNT, TCP_KEEPINTERVAL, SO_REUSEADDR, SO_SNDBUF, SO_RCVBUF, TCP_KEEPIDLE, SO_INCOMING_NAPI_ID, TCP_QUICKACK, SO_KEEPALIVE, SO_REUSEPORT]
Notice that the contains
check evaluates to false, however the stringified options DO INCLUDE TCP_KEEPIDLE
. Maybe this helps in finding the issue. My guess is this has something to do with build-time class initialization and code optimization, but I don't fully understand this behaviour.
Steps to reproduce the issue
Please include both build steps as well as run steps
- Unpack the application: tcp-keepidle-repro.zip
mvn native:compile
java -jar target/tcp-keepaliveidle-0.0.1-SNAPSHOT.jar
-> workstarget/tcp-keepaliveidle
-> fails
Describe GraalVM and your environment:
- GraalVM version:
OpenJDK 64-Bit Server VM GraalVM CE 17.0.7-dev+4.1 (build 17.0.7+4-jvmci-23.0-b10, mixed mode, sharing)
- JDK major version:
17
- OS: Ubuntu 22.04
- Architecture: AMD64