Skip to content

Instantly share code, notes, and snippets.

@borkdude
Last active August 31, 2020 21:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save borkdude/768eb5d01085944190e5eb485fd4737a to your computer and use it in GitHub Desktop.
Save borkdude/768eb5d01085944190e5eb485fd4737a to your computer and use it in GitHub Desktop.
clojure.test.check.random + GraalVM native-image randomization issue

Repro

Clone: $ git clone https://github.com/clojure/test.check.git && cd test.check

Make main class:

echo "(ns foo (:gen-class)) (require '[clojure.test.check.random :as r]) (defn -main [& args] (prn (r/rand-long (r/make-random))))" > src/main/clojure/foo.clj

Make classes dir: mkdir -p classes

AOT compile:

$ clojure -J-Dclojure.compiler.direct.linking=true -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}}}' -e "(require 'foo) (compile 'foo) (compile 'clojure.test.check.random)"

Run on JVM, observe that random works:

$ java -cp classes:$(clojure -Spath) foo
2641378700178763226
$ java -cp classes:$(clojure -Spath) foo
-8419687867193585516

Compile with GraalVM native-image:

$ $GRAALVM_HOME/bin/native-image foo --no-fallback --no-server --report-unsupported-elements-at-runtime --initialize-at-build-time -cp $(clojure -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"}} :paths ["classes"]}' -Spath)

Run binary, observe that random doesn't work:

$ ./foo
-4433304172342098913
$ ./foo
-4433304172342098913

Workaround:

(def next-rng
  "Returns a random-number generator. Successive calls should return
  independent results."
  (let [a (atom (delay (r/make-java-util-splittable-random (System/currentTimeMillis))))
        thread-local
        (proxy [ThreadLocal] []
          (initialValue []
            (first (r/split (swap! a #(second (r/split (force %))))))))]
    (fn []
      (let [rng (.get thread-local)
            [rng1 rng2] (r/split rng)]
        (.set thread-local rng2)
        rng1))))

(defn make-random
  "Given an optional Long seed, returns an object that satisfies the
  IRandom protocol."
  ([] (next-rng))
  ([seed] (r/make-java-util-splittable-random seed)))

With this code patched (either directly or through alter-var-root the GraalVM binary will work correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment