scalameta / sbt-native-image

Plugin to generate native-image binaries with sbt
251 stars 22 forks source link

native-image 21.1.0 fails on `scala.util.Random$` #27

Open taig opened 3 years ago

taig commented 3 years ago

GraalVM 21.1.0 has just been released, but my builds are failing unfortunately.

Error: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  Object has been initialized by the scala.util.Random$ class initializer with a trace: 
    at java.util.Random.<init>(Random.java:105)
    at scala.util.Random.<init>(Random.scala:30)
    at scala.util.Random$.<init>(Random.scala:260)
    at scala.util.Random$.<clinit>(Random.scala:260)
. Try avoiding to initialize the class that caused initialization of the object. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
Detailed message:
Trace: Object was reached by 
    reading field scala.util.Random.self of
        constant scala.util.Random$@5e16dff3 reached by 
    scanning method org.http4s.client.PoolManager.$anonfun$borrow$10(PoolManager.scala:199)
Call path from entry point to org.http4s.client.PoolManager.$anonfun$borrow$10(Iterable): 
    at org.http4s.client.PoolManager.$anonfun$borrow$10(PoolManager.scala:199)
    at org.http4s.client.PoolManager$$Lambda$2848/0x00000007c26b5c40.apply(Unknown Source)
    at scala.collection.Iterator$$anon$22.next(Iterator.scala:1008)
    at scala.collection.convert.JavaCollectionWrappers$IteratorWrapper.next(JavaCollectionWrappers.scala:29)
    at com.oracle.svm.jni.access.JNIReflectionDictionary.unsetEntryPoints(JNIReflectionDictionary.java:178)
    at com.oracle.svm.jni.functions.JNIFunctions.UnregisterNatives(JNIFunctions.java:398)
    at com.oracle.svm.core.code.IsolateEnterStub.JNIFunctions_UnregisterNatives_07af9442aa98f893dd700b47b363fa08a3f7e240(generated:0)

Steps to reproduce the behavior

  1. Set GraalVM version to 21.1.0
  2. Run sbt/nativeImage on code that references scala.util.Random$

Solution

scala.util.Random$ extends scala.util.Random and thereby causes a static initialization of java.util.Random which is not allowed, as the error message above suggests. I believe we should therefore add --initialize-at-run-time=scala.util.Random$ to the default options of this plugin.

olafurpg commented 3 years ago

Thank you for reporting! Can you confirm that --initialize-at-run-time=scala.util.Random$ fixes the problem? We can certainly enable something like that by default in this plugin.

taig commented 3 years ago

After adding the option to my build, the native-image generation passed without issues again and the executables are doing fine in production. As this is a Scala-related issue, this project seems to be the best place to handle it. However, I have poor understanding of the native-image mechanics and don't fully get why this change became necessary, so I figured I'll contribute this as a suggestion and get some more eyes on it.

The issue did of course also pop up in numerous Java libraries which also appear to be resolved via runtime init https://github.com/quarkusio/quarkus/issues/14904.

If you agree with the approach, I would be happy to submit a PR.