I'm getting the locking issue while compiling a library (datalevin) with GraalVM native-image. Haven't dug deeply into this yet. Could be that some AOT-ed thing is left on the classpath that brings in the old locking stuff, but the source which occurs in the error output is not AOT-ed I believe: https://github.com/borkdude/datalevin-native
Hmm, I believe this repros it:
(defprotocol IFoo
(store [_]))
(deftype Foo [^:volatile-mutable ^long max-gt]
IFoo
(store [_]
(locking max-gt
(println "Stored!"))))
(defn -main [& _args]
(let [foo (Foo. 10)]
(store foo))
Error: unbalanced monitors: mismatch at monitorexit, 7|Invoke#Numbers.num != 52|Invoke#Numbers.num
Detailed message:
Call path from entry point to borkdude.datalevin_native.main.Foo.store():
at borkdude.datalevin_native.main.Foo.store(main.clj:14)
I'll make a dedicated repro repo in a few hours, and I'll add some comment to CLJ-1472 (cc @alexmiller)
Aha!
When I remove the ^long
type hint, then it compiles:
(defprotocol IFoo
(store [_]))
(deftype Foo [^long max-gt]
IFoo
(store [_]
(locking max-gt
(println "Stored!"))))
(defn -main [& _args]
(let [foo (Foo. 10)]
(store foo)))
just file a new ticket
and link to CLJ-1472
wait, you can't lock on a primitive long - it has to be an object
that code doesn't make sense
yeah, I figured the same. it comes from here: https://github.com/juji-io/datalevin/blob/0588dde496b18ced06fed036db3f969c35c69ef8/src/datalevin/storage.clj#L226
yeah, that's bad
so it does not work, but it doesn't fail in the JVM either?
my guess would be that in some cases the primitive long is getting up cast. that's the only way it could work (but locking on a Long value is still a bad idea). this code is just wrong.
the Java numeric value objects can be cached around 0 and that means the scope of your Long sharing can escape your own code (similarly, you should never lock on a String instance which might be interned)
:thumbsup: I'll make an issue with this conversation in their repo
it's best to make an explicit lock Object