Clojure

once the compiler pops the dynamic classloader from the stack, attempts to read record reader literals will fail

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Minor Minor
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Approval:
    Triaged

Description

reproduction case

java -jar target/clojure-1.7.0-master-SNAPSHOT.jar -e "(do (ns foo.bar) (defrecord Foo []) (defn -main [] (prn (->Foo)) (read-string \"#foo.bar.Foo[]\")))" -m foo.bar

result

#'foo.bar/-main
#foo.bar.Foo{}
Exception in thread "main" java.lang.ClassNotFoundException: foo.bar.Foo
	at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:340)
	at clojure.lang.RT.classForNameNonLoading(RT.java:2076)
	at clojure.lang.LispReader$CtorReader.readRecord(LispReader.java:1195)
	at clojure.lang.LispReader$CtorReader.invoke(LispReader.java:1164)
	at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:609)
	at clojure.lang.LispReader.read(LispReader.java:183)
	at clojure.lang.RT.readString(RT.java:1737)
	at clojure.core$read_string.invoke(core.clj:3497)
	at foo.bar$_main.invoke(NO_SOURCE_FILE:1)
	at clojure.lang.Var.invoke(Var.java:375)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.Var.applyTo(Var.java:700)
	at clojure.core$apply.invoke(core.clj:624)
	at clojure.main$main_opt.invoke(main.clj:315)
	at clojure.main$main.doInvoke(main.clj:420)
	at clojure.lang.RestFn.invoke(RestFn.java:457)
	at clojure.lang.Var.invoke(Var.java:394)
	at clojure.lang.AFn.applyToHelper(AFn.java:165)
	at clojure.lang.Var.applyTo(Var.java:700)
	at clojure.main.main(main.java:37)

what happens is the evaluator pushes a dynamicclassloader, evaluates some code, then -m foo.bar causes foo.bar/-main to be called, which tries to read in a literal for the just defined record, but it fails because when foo.bar/-main is called clojure.lang.Compiler/LOADER is unbound so RT uses the sun.misc classloader to try and find the class, which it knows nothing about

Activity

Hide
Kevin Downey added a comment -

this means that you cannot depend on ever being able to deserialize a record with read unless you are at the repl (the only place clojure.lang.Compiler/LOADER is guaranteed to be bound).

1. print/read support for records is broken
2. behavior is inconsistent between the repl and other environments
which will drive people crazy when the try to figure out why their code isn't working

Show
Kevin Downey added a comment - this means that you cannot depend on ever being able to deserialize a record with read unless you are at the repl (the only place clojure.lang.Compiler/LOADER is guaranteed to be bound). 1. print/read support for records is broken 2. behavior is inconsistent between the repl and other environments which will drive people crazy when the try to figure out why their code isn't working
Hide
Alex Miller added a comment -

I would appreciate more understanding about how this affects code run in a more normal scenario (than calling clojure.main with -e and -m).

Show
Alex Miller added a comment - I would appreciate more understanding about how this affects code run in a more normal scenario (than calling clojure.main with -e and -m).
Hide
Kevin Downey added a comment -

https://gist.githubusercontent.com/anonymous/bafde69c99e0be63988d/raw/736d14d98030f48b6a65ca0bfdc3c81fb44e1789/gistfile1.txt is an hour long irc log where someone was having a problem after they switched their app from aot compilation to launch via -m, which I tracked down to this issue.

Show
Kevin Downey added a comment - https://gist.githubusercontent.com/anonymous/bafde69c99e0be63988d/raw/736d14d98030f48b6a65ca0bfdc3c81fb44e1789/gistfile1.txt is an hour long irc log where someone was having a problem after they switched their app from aot compilation to launch via -m, which I tracked down to this issue.
Hide
David Pidcock added a comment -

This also affects me running
lein ring server

I threw this test code in my handler.clj

(defrecord Test [id])

(def example-test (pr-str (->Test 1)))

(defroutes app-routes
(GET "/test" [] (read-string example-test)))

When I run this in the REPL, it works.
But I get ClassNotFound when I browse to "/test".

I thought I'd done something stupid, until I found this bug. (Well - I could still be doing something stupid, of course).

Show
David Pidcock added a comment - This also affects me running lein ring server I threw this test code in my handler.clj (defrecord Test [id]) (def example-test (pr-str (->Test 1))) (defroutes app-routes (GET "/test" [] (read-string example-test))) When I run this in the REPL, it works. But I get ClassNotFound when I browse to "/test". I thought I'd done something stupid, until I found this bug. (Well - I could still be doing something stupid, of course).
Hide
Michael Fogleman added a comment -

Nicola Mometto helpfully pointed out that CLJ-1413 seems to be the same issue as this.

http://dev.clojure.org/jira/browse/CLJ-1413

Show
Michael Fogleman added a comment - Nicola Mometto helpfully pointed out that CLJ-1413 seems to be the same issue as this. http://dev.clojure.org/jira/browse/CLJ-1413
Hide
Michael Fogleman added a comment -

In the other issue, Lars Bohl has a reproducible example of a very simple or even simplest possible case.

Show
Michael Fogleman added a comment - In the other issue, Lars Bohl has a reproducible example of a very simple or even simplest possible case.

People

Vote (6)
Watch (6)

Dates

  • Created:
    Updated: