Graal: IPv6 static native image throws java.net.SocketException: Protocol family unavailable

Created on 21 Apr 2020  路  8Comments  路  Source: oracle/graal

Describe the issue
Executing a static native image binary built using muslC throws a SocketException when using an IPv6 address

Steps to reproduce the issue
Please include both build steps as well as run steps

  1. Install scala build tool SBT https://www.scala-sbt.org/download.html
  2. Clone https://github.com/drocsid/https_example
  3. Execute the script native-image-build-cmd.sh which builds a static image using muslC
  4. Execute the nativeImage binary and get the stack trace.
java.net.SocketException: Protocol family unavailable
    at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_ARRAY:Ljava_net_SocketException_2_0002e_0003cinit_0003e_00028Ljava_lang_String_2_00029V(JNIJavaCallWrappers.java:0)
    at com.oracle.svm.jni.functions.JNIFunctions$NewObjectWithObjectArrayArgFunctionPointer.invoke(JNIFunctions.java)
    at com.oracle.svm.jni.functions.JNIFunctions.ThrowNew(JNIFunctions.java:801)
    at sun.nio.ch.Net.bind0(Net.java)
    at sun.nio.ch.Net.bind(Net.java:455)
    at sun.nio.ch.Net.bind(Net.java:447)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:227)
    at java.nio.channels.ServerSocketChannel.bind(ServerSocketChannel.java:162)
    at org.http4s.blaze.channel.nio1.NIO1SocketServerGroup.$anonfun$bind$1(NIO1SocketServerGroup.scala:217)
    at scala.util.Try$.apply(Try.scala:210)
    at org.http4s.blaze.channel.nio1.NIO1SocketServerGroup.bind(NIO1SocketServerGroup.scala:216)
    at org.http4s.blaze.channel.nio1.NIO1SocketServerGroup$$anon$1.bind(NIO1SocketServerGroup.scala:79)
    at org.http4s.server.blaze.BlazeServerBuilder.$anonfun$resource$5(BlazeServerBuilder.scala:341)
    at scala.Function1.$anonfun$andThen$1(Function1.scala:85)
    at scala.Function1.$anonfun$andThen$1(Function1.scala:85)
    at cats.effect.IO$Map.apply(IO.scala:1504)
    at cats.effect.IO$Map.apply(IO.scala:1502)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:142)
    at cats.effect.internals.IORunLoop$.startCancelable(IORunLoop.scala:41)
    at cats.effect.internals.IOBracket$BracketStart.run(IOBracket.scala:88)
    at cats.effect.internals.Trampoline.cats$effect$internals$Trampoline$$immediateLoop(Trampoline.scala:67)
    at cats.effect.internals.Trampoline.startLoop(Trampoline.scala:35)
    at cats.effect.internals.TrampolineEC$JVMTrampoline.super$startLoop(TrampolineEC.scala:89)
    at cats.effect.internals.TrampolineEC$JVMTrampoline.$anonfun$startLoop$1(TrampolineEC.scala:89)
    at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
    at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:94)
    at cats.effect.internals.TrampolineEC$JVMTrampoline.startLoop(TrampolineEC.scala:89)
    at cats.effect.internals.Trampoline.execute(Trampoline.scala:43)
    at cats.effect.internals.TrampolineEC.execute(TrampolineEC.scala:42)
    at cats.effect.internals.IOBracket$BracketStart.apply(IOBracket.scala:69)
    at cats.effect.internals.IOBracket$BracketStart.apply(IOBracket.scala:49)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:139)
    at cats.effect.internals.IORunLoop$.start(IORunLoop.scala:34)
    at cats.effect.internals.IOBracket$.$anonfun$apply$1(IOBracket.scala:42)
    at cats.effect.internals.IOBracket$.$anonfun$apply$1$adapted(IOBracket.scala:32)
    at cats.effect.internals.IORunLoop$RestartCallback.start(IORunLoop.scala:345)
    at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:122)
    at cats.effect.internals.IORunLoop$RestartCallback.signal(IORunLoop.scala:359)
    at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:380)
    at cats.effect.internals.IORunLoop$RestartCallback.apply(IORunLoop.scala:323)
    at cats.effect.internals.IOShift$Tick.run(IOShift.scala:35)
    at cats.effect.internals.PoolUtils$$anon$2$$anon$3.run(PoolUtils.scala:52)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.lang.Thread.run(Thread.java:834)
    at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:527)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)

Describe GraalVM and your environment:
java --version
openjdk 11.0.6 2020-01-14
OpenJDK Runtime Environment GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02)
OpenJDK 64-Bit Server VM GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02, mixed mode, sharing)

OS: Debian 4.19.0-4-amd64 bullseye
Architecture: AMD64

More details
https://github.com/drocsid/https_example/blob/aab787f5ce12e621002f1e661a2972f63df351c8/README.md

bug native-image

Most helpful comment

All 8 comments

@drocsid I have found the cause for this issue. It affects all static native-images, regardless of underlying libc.
On Linux, during the initialization of the net library, IPv6 support is checked. Part of that check is a call to jint IPv6_supported() from net_util_md.c. Eventually, the function will check if a symbol inet_pton is available:

ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
close(fd);
if (ipv6_fn == NULL ) {
    return JNI_FALSE;
} else {
    return JNI_TRUE;
}

Since we supply our own libjvm, we can see the source of JVM_FindLibraryEntry:

JNIEXPORT void* JNICALL JVM_FindLibraryEntry(void* handle, const char* name) {
    return dlsym(handle, name);
}

The issue lies in the call to dlsym, a function for finding a symbol in dynamic libraries, in a static binary. The symbol will not be found and the JDK will think the necessary function for IPv6 is not available.
I will post an update once a fix for this is done. I have not been able to find a temporary workaround that doesn't involve recompiling Graal.

Congratulations @gradinac ! How did you follow the initialization ? Were you using strace , dtrace, or similar? I think the graal team should be happy to fix this on a future release. I would expect that IPv6 should work for static native-images.

@drocsid I have submitted an initial PR to fix this, and if accepted, will see if we can get it ported for the upcoming release.
The way I tracked it down is by going through the JDK sources and backtracking from the error message that we were getting to where the issue begun. gdb also helped to see the values of variables at runtime, which then meant the wrong result must have occurred during libnet initialization.

Thanks @gradinac ! Let me know if you'd like me to test it against my build.

Could you please try running your test with muslC 1.2.0. It looks like they have added some support for RTLD_DEFAULT in the latest version.

https://git.musl-libc.org/cgit/musl/tag/?h=v1.2.0

@bobvandette I will test. But then against the current version of graal?

@bobvandette yes it fails the test for musl-1.2.0. https://github.com/drocsid/https_example

Was this page helpful?
0 / 5 - 0 ratings