Clojure

Exceptions thrown in user namespace initialisation in Clojure 1.10.0 are missing the full stacktrace

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: Release 1.10
  • Fix Version/s: Release 1.10
  • Component/s: None
  • Patch:
    Code
  • Approval:
    Ok

Description

The cause stack is swallowed when exceptions are thrown during initialization of the user namespace. Compiler exceptions thrown after this point have the full stack trace.

The behavior changed between 1.10 alpha6 and alpha7.

➜  ~ cat > /tmp/user.clj
(require 'nonexistent)

➜  ~ clj -Sdeps '{:paths ["/tmp"] :deps {org.clojure/clojure {:mvn/version "1.10.0-alpha6"}}}'
Exception in thread "main" java.lang.ExceptionInInitializerError
	at clojure.main.<clinit>(main.java:20)
Caused by: java.io.FileNotFoundException: Could not locate nonexistent__init.class or nonexistent.clj on classpath., compiling:(user.clj:1:1)
	at clojure.lang.Compiler.load(Compiler.java:7533)
	at clojure.lang.RT.loadResourceScript(RT.java:379)
	at clojure.lang.RT.loadResourceScript(RT.java:366)
	at clojure.lang.RT.maybeLoadResourceScript(RT.java:362)
	at clojure.lang.RT.doInit(RT.java:482)
	at clojure.lang.RT.<clinit>(RT.java:336)
	... 1 more
Caused by: java.io.FileNotFoundException: Could not locate nonexistent__init.class or nonexistent.clj on classpath.
	at clojure.lang.RT.load(RT.java:463)
	at clojure.lang.RT.load(RT.java:426)
	at clojure.core$load$fn__6629.invoke(core.clj:6061)
	at clojure.core$load.invokeStatic(core.clj:6060)
	at clojure.core$load.doInvoke(core.clj:6044)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5863)
	at clojure.core$load_one.invoke(core.clj:5858)
	at clojure.core$load_lib$fn__6574.invoke(core.clj:5903)
	at clojure.core$load_lib.invokeStatic(core.clj:5902)
	at clojure.core$load_lib.doInvoke(core.clj:5883)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$load_libs.invokeStatic(core.clj:5940)
	at clojure.core$load_libs.doInvoke(core.clj:5924)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.core$require.invokeStatic(core.clj:5962)
	at clojure.core$require.doInvoke(core.clj:5962)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at user$eval1.invokeStatic(user.clj:1)
	at user$eval1.invoke(user.clj:1)
	at clojure.lang.Compiler.eval(Compiler.java:7069)
	at clojure.lang.Compiler.load(Compiler.java:7521)
	... 6 more

➜  ~ clj -Sdeps '{:paths ["/tmp"] :deps {org.clojure/clojure {:mvn/version "1.10.0-alpha7"}}}'
Exception in thread "main" java.lang.ExceptionInInitializerError
	at clojure.main.<clinit>(main.java:20)

Cause: The changes in CLJ-2373 for CompilerException.toString() use calls to RT. In the scenario above, we are in the path of RT static initialization so RT has not yet been loaded. Thus the toString() logic triggers NoClassDefFoundError while building the message in the toString() of the actual exception.

Approach: Stop using RT.get() in the toString() and use IPersistentMap.valAt() directly.

Patch: clj-2427-2.patch

  1. clj-2427.patch
    13/Nov/18 10:58 AM
    2 kB
    Alex Miller
  2. clj-2427-2.patch
    13/Nov/18 11:45 AM
    3 kB
    Alex Miller

Activity

Hide
Ghadi Shayban added a comment -

Thanks Daniel – I edited the repro case a bit.

Show
Ghadi Shayban added a comment - Thanks Daniel – I edited the repro case a bit.
Hide
Alex Miller added a comment -

This is due to the Compiler$CompilerException.toString() change in CLJ-2373, looking at it.

Show
Alex Miller added a comment - This is due to the Compiler$CompilerException.toString() change in CLJ-2373, looking at it.
Hide
Alex Miller added a comment -

-2 fixes some test failures - oops!

Show
Alex Miller added a comment - -2 fixes some test failures - oops!

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: