Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native image - java.lang.NoClassDefFoundError when specifying -H:JNIConfigurationFiles #17729

Open
ruffythepirate opened this issue Jun 7, 2021 · 4 comments
Labels
area/kotlin kind/bug Something isn't working

Comments

@ruffythepirate
Copy link

Describe the bug

In trying to configure JNI enabled classes for GraalVM using the addition build arg -H:JNIConfigurationFiles it was noticed that Quarkus seemingly throws an unrelated error:

Running Quarkus native-image plugin on GraalVM Version 21.0.0.2 (Java Version 11.0.10+8-jvmci-21.0-b06)
docker run --env LANG=C --user 1000:1000 --rm -v /home/johan/sandbox/poc-jni-whitelist/build/poc-jni-whitelist-1.0.0-SNAPSHOT-native-image-source-jar:/project:z quay.io/quarkus/ubi-quarkus-native-image:21.0-java11 -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=1 -J-Duser.language=en -J-Duser.country=US -J-Dfile.encoding=UTF-8 -H:JNIConfigurationFiles=jniconfig.json --initialize-at-build-time= -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy\$BySpaceAndTime -H:+JNI -H:+AllowFoldMethods -jar poc-jni-whitelist-1.0.0-SNAPSHOT-runner.jar -H:FallbackThreshold=0 -H:+ReportExceptionStackTraces -H:-AddAllCharsets -H:EnableURLProtocols=http --no-server -H:-UseServiceLoaderFeature -H:+StackTrace poc-jni-whitelist-1.0.0-SNAPSHOT-runner
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]    classlist:   2,134.09 ms,  0.94 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]        (cap):     704.53 ms,  0.94 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]        setup:   2,541.62 ms,  0.94 GB
13:19:45,136 INFO  [org.jbo.threads] JBoss Threads version 3.2.0.Final
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]     (clinit):     675.87 ms,  2.69 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]   (typeflow):  11,142.43 ms,  2.69 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]    (objects):  10,228.69 ms,  2.69 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]   (features):     570.82 ms,  2.69 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]     analysis:  23,735.70 ms,  2.69 GB
[poc-jni-whitelist-1.0.0-SNAPSHOT-runner:27]     universe:   1,465.24 ms,  2.69 GB
Fatal error:java.lang.NoClassDefFoundError
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
        at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:603)
        at java.base/java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1006)
        at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:488)
        at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:370)
        at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:529)
        at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:119)
        at com.oracle.svm.hosted.NativeImageGeneratorRunner$JDK9Plus.main(NativeImageGeneratorRunner.java:561)
Caused by: java.lang.NoClassDefFoundError: io/netty/internal/tcnative/SSLPrivateKeyMethod
        at jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVM.getDeclaredMethods(Native Method)
        at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.getDeclaredMethods(HotSpotResolvedObjectTypeImpl.java:987)
        at com.oracle.svm.jni.access.JNIAccessibleMethod.anyMatchIgnoreReturnType(JNIAccessibleMethod.java:139)
        at com.oracle.svm.jni.access.JNIAccessibleMember.findHidingSubclasses(JNIAccessibleMember.java:103)
        at com.oracle.svm.jni.access.JNIAccessibleMember.findHidingSubclasses(JNIAccessibleMember.java:110)
        at com.oracle.svm.jni.access.JNIAccessibleMember.setHidingSubclasses(JNIAccessibleMember.java:83)
        at com.oracle.svm.jni.access.JNIAccessibleMethod.finishBeforeCompilation(JNIAccessibleMethod.java:135)
        at com.oracle.svm.jni.access.JNIAccessFeature.beforeCompilation(JNIAccessFeature.java:350)
        at com.oracle.svm.hosted.NativeImageGenerator.lambda$doRun$2(NativeImageGenerator.java:619)
        at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:70)
        at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:619)
        at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:476)
        at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407)
        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:183)
Caused by: java.lang.ClassNotFoundException: io.netty.internal.tcnative.SSLPrivateKeyMethod
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        ... 18 more
Error: Image build request failed with exit status 1

Expected behavior

Either that the build will work fine and the JNI Configuration files are provided to GraalVM, or that a more descriptive error message explain what's wrong.

Actual behavior

The build fails, citing not finding a class that has seemingly nothing to do with the JNI configuration.

To Reproduce

Here's a small project describing the error: https://github.com/radiosphere/poc-jni-whitelist . Running ./gradlew clean buildNative will generate an error (at least when using java 11, GraalVM 21.1.0)

Configuration

quarkus.native.additional-build-args=-H:JNIConfigurationFiles=jniconfig.json

Environment (please complete the following information):

Output of uname -a or ver

Linux johan-ThinkPad-T14s-Gen-1 5.8.0-55-generic #62~20.04.1-Ubuntu SMP Wed Jun 2 08:55:04 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment GraalVM CE 21.1.0 (build 11.0.11+8-jvmci-21.1-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.1.0 (build 11.0.11+8-jvmci-21.1-b05, mixed mode, sharing)

Quarkus version or git rev

1.13.6.Final

Build tool (ie. output of mvnw --version or gradlew --version)

Initialized native services in: /home/johan/.gradle/native

------------------------------------------------------------
Gradle 6.8.3
------------------------------------------------------------

Build time:   2021-02-22 16:13:28 UTC
Revision:     9e26b4a9ebb910eaa1b8da8ff8575e514bc61c78

Kotlin:       1.4.20
Groovy:       2.5.12
Ant:          Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM:          11.0.11 (GraalVM Community 11.0.11+8-jvmci-21.1-b05)
OS:           Linux 5.8.0-55-generic amd64

Additional context

This problem was discovered when trying to enable native SSL termination for Netty that is running under Quarkus (the Netty listener is configured using our code, and not by Quarkus, but Quarkus is doing a lot of other framework related things in the project.). Seemingly there's an open issue in Netty to use OpenSSL in native GraalVM.

@ruffythepirate ruffythepirate added the kind/bug Something isn't working label Jun 7, 2021
@quarkus-bot
Copy link

quarkus-bot bot commented Jun 7, 2021

/cc @evanchooly

@gsmet
Copy link
Member

gsmet commented Jun 10, 2021

My guess is that defining a JNI config overrides what we are doing at the Quarkus level.

I'm not really sure we can do anything about it. Maybe try to use a Quarkus extension instead?

@ruffythepirate
Copy link
Author

Hi Guillaume,

Thank you for looking into this!

My impression after reading the GraalVM documentation is that the setting primarily marks that some metadata should not be pruned away upon building the native image to allow JNI to function well.

Now if I've understood Quarkus correctly it's doing its magic when generating the .class files (I might be wrong here), so when I think about it I suppose it makes sense that if Quarkus would already cleanup specific classes before GraalVM is told to keep it, there's not much GraalVM would be able to do. But perhaps it would be possible for Quarkus to be conscious of the JNI classes and simply not remove them in the class generation phase.

Using an extension would have been really nice and there is one available for Netty which works fine in general. Unfortunately I've found non that enables the OpenSSL support which is what we want to do for Netty. Having the OpenSSL enabled gives a considerable performance boost.

In quarkus in general I do find references to OpenSSL, but only if it's available, and that's the tricky part. Making OpenSSL available.

@himanshumps
Copy link

Can we use openssl / boringssl with Quarkus in the native image?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/kotlin kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants