*read-eval* vulnerability

814 views
Skip to first unread message

Takahiro Hozumi

unread,
Jan 30, 2013, 2:02:54 AM1/30/13
to Clojure
As more and more projects are using edn format for config,
communication and etc, I think that default value of *read-eval*,
which is true, is source of vulnerability such as recently reported
ring issue [1].
And I don't understand why read-string depends on *read-eval* instead
of argument.
I believe optional argument is more preferable.
What do you think?

[1] Ring 1.0.3 / 1.1.7 released to fix security flaw
https://groups.google.com/group/clojure/browse_thread/thread/7b0fe662867b9124

Andy Fingerhut

unread,
Jan 30, 2013, 9:55:59 AM1/30/13
to clo...@googlegroups.com
This isn't what you are asking, but I wanted to make a comment that there is a proposed patch to Clojure attached to ticket CLJ-904 that adds warnings to read and read-string about how their behavior depends upon the value of *read-eval*:

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

Also, one of the examples for read on ClojureDocs.org defines a 'read-from-file-safely' function showing how to avoid eval behavior:

http://clojuredocs.org/clojure_core/clojure.core/read

Andy

Chas Emerick

unread,
Jan 30, 2013, 10:04:06 AM1/30/13
to clo...@googlegroups.com
This is exactly the thread that I meant to start a couple of weeks ago. Thanks for giving me the kick in the pants, Takahiro. :-)

What brought the issue to the fore for me:

* a greatly increased interest in security issues due to my own work's requirements
* the most recent arbitrary code execution issues that the Rails community has had to weather
* Building and maintaining Friend (http://github.com/cemerick/friend) has gradually brought me into contact with a handful of suitably experienced people that have done security reviews (none formal or published, BTW) of the Clojure web stack.

In each of the three times I've been fortunate to discuss those reviews with their instigators, the first thing that comes up is *read-eval*. Perhaps not surprising — we've all known that its default is an open barn door. The sole thread I could dig up that discusses this is http://groups.google.com/group/clojure/browse_frm/thread/1bd6b66b51406ec9?tvc=1, where the common refrain is simply "you should bind *read-eval* to false when reading data from unknown sources". Despite this not being news, recent events and certain changes in my foci have made it a newly-important issue, at least to me.

Takahiro is exactly right that the growing usage of Clojure data / edn as a common serialization format for e.g. web service APIs makes the default of *read-eval* very, very relevant; IMO, despite any concerns re: breaking existing code. On that front, *read-eval* affects only the #= construction, a facility that is, IIRC, purposefully undocumented. This lack of documentation is good insofar as few people have used #=, but it has also left undocumented an implementation detail of the reader that ships with a dangerous default (see http://dev.clojure.org/jira/browse/CLJ-904).

The advice and necessity to tighten up *read-eval* as "good practice" is a design fault. There are things that authors of certain key Clojure libraries can do to fix this up as a side effect of using those libraries, but it would obviously be ideal for Clojure/core to address the policy proactively. Otherwise, I'm certain that a time will come when people not steeped in Clojure arcana will be deploying vulnerable applications and services. Unfortunately, I suspect that time has long since arrived...we just don't (yet?) have the eyeballs and juice that the Rails community has to produce controversy.

Cheers,

- Chas
> --
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Marek Šrank

unread,
Jan 30, 2013, 10:18:46 AM1/30/13
to clo...@googlegroups.com, fat...@googlemail.com
The most simple thing would be to change the default value of *read-eval* to false...

Marek

Kyle R. Burton

unread,
Jan 30, 2013, 10:25:46 AM1/30/13
to clo...@googlegroups.com, fat...@googlemail.com
On Wed, Jan 30, 2013 at 10:18 AM, Marek Šrank <markus...@gmail.com> wrote:
The most simple thing would be to change the default value of *read-eval* to false...


Understanding that this may break existing code (how much?), I think it would reflect well on the community to make decisions to improve safety and security, especially with respect to defaults like this.  Avoiding surprises after deployment is a virtue in my option. 

+1

Regards,

Kyle Burton

--
Twitter: @kyleburton
Github: https://github.com/kyleburton
Blog: http://asymmetrical-view.com/
Fun: http://snapclean.me/

Paul deGrandis

unread,
Jan 30, 2013, 10:36:23 AM1/30/13
to clo...@googlegroups.com, fat...@googlemail.com
I like the idea of setting the default to false.  This potentially does break some code, but perhaps it breaks unknowingly insecure code - which is a pretty big bonus.
I'd love it if I upgraded to a new release of Clojure and my app toppled down because of my own shortsightedness.

An additional idea is to add an optional second argument to read-string, which does the binding for you.

Regards,
Paul

Norman Richards

unread,
Jan 30, 2013, 11:42:57 AM1/30/13
to clo...@googlegroups.com
On Wed, Jan 30, 2013 at 1:02 AM, Takahiro Hozumi <fat...@googlemail.com> wrote:
As more and more projects are using edn format for config,
communication and etc, I think that default value of *read-eval*,
which is true, is source of vulnerability such as recently reported
ring issue [1].

Slight diversion here - what is the approved and safe way to read data from an untrusted source?  I had a task this week which required data to to be read via an API.  I wanted to use clojure data/EDN, and ended up with three primary issues:

1 - *read-eval*, which I bound to false
2 - data literals - I don't know which data literals are truly safe from an external source.  I rebound *data-readers* to make sure only the system readers were around, which I assume are thought to be safe
3 - read-string only reads one expression, silently ignoring additional characters.  I assume I could solve this using read and checking for additional items and raising an error if more expressions were received than expected

In the end, I re-implemented this API using JSON, where there are no safety issues parsing data.  This is an unfortunate decision, and I'd like to enable the clojure data version.  I'm just not sure whether or not using read/read-string is intended to be a safe reader in the long term.  If it's not, maybe we need a set of functions that are blessed for use with untrusted data?


Andy Fingerhut

unread,
Jan 30, 2013, 11:52:14 AM1/30/13
to clo...@googlegroups.com
Out of curiosity, I made a patch to Clojure that causes the default value of *read-eval* to be false instead of true, to see if any of the tests pass, and to let other people try it out in case it breaks things that would be surprising and/or disruptive. It is attached to this new ticket:

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

I found this behavior from one of the unit tests included with Clojure. Does it surprise anyone, or look like it would break something important?

% java -cp clojure.jar clojure.main
Clojure 1.5.0-master-SNAPSHOT
user=> '(list + 1 2 3)
(list + 1 2 3)
user=> (eval '(list + 1 2 3))
(#<core$_PLUS_ clojure.core$_PLUS_@11dfc8a0> 1 2 3)
user=> (eval (eval '(list + 1 2 3)))
RuntimeException EvalReader not allowed when *read-eval* is false. clojure.lang.Util.runtimeException (Util.java:219)

The last expression evaluates to 6 when *read-eval* is true, with no exception.

Andy

Michael Fogus

unread,
Jan 30, 2013, 12:23:00 PM1/30/13
to Clojure
> RuntimeException EvalReader not allowed when *read-eval* is false.

The problem is that the second eval gets (<the actual + function> 1 2
3) which invokes the right pathway triggering the exception. You can
trigger the same exception by:

(binding [*read-eval* false] (eval (list + 1 2 3)))

People are not sending actual functions across the wire, so the only
way to trigger this is to do some kind of pre-processing of symbols to
functions or perhaps:

(binding [*read-eval* false] (eval '(eval (quote (+ 1 2 3)))))
;;=> 6

Whoops!

Maybe setting *read-eval* to false is not enough.

Alex Baranosky

unread,
Jan 30, 2013, 12:30:53 PM1/30/13
to clo...@googlegroups.com
"I like the idea of setting the default to false."
I'd like to add a voice of agreement for this vote.

Alex

Michael Fogus

unread,
Jan 30, 2013, 12:49:46 PM1/30/13
to Clojure
Although let me say that I agree with false being the default. I'm
not saying that is a bad idea, only that we need to be careful if
evaling what comes over... but I guess that is obvious and if not then
we get what we deserve. ;-)
--
-- http://blog.fogus.me
-- http://github.com/fogus
--

Phil Hagelberg

unread,
Jan 30, 2013, 1:23:24 PM1/30/13
to clo...@googlegroups.com

Kyle R. Burton writes:

> Understanding that this may break existing code (how much?), I think it
> would reflect well on the community to make decisions to improve safety and
> security, especially with respect to defaults like this. Avoiding
> surprises after deployment is a virtue in my option.

Considering that *read-eval* is undocumented, I think that makes for a
much stronger case for changing its behaviour. Code that relies on
*read-eval* defaulting to true is relying on an undocumented
implementation detail, so breakage surrounding it should not be terribly
surprising.

If the default is not changed for whatever reason (which I believe would
be a bad decision, but whatever) then at the very least it should be
documented. Having a potential source of fatal exploits which can only
be protected against by tribal knowledge is a really unfortunate
situation.

-Phil

Chas Emerick

unread,
Jan 30, 2013, 1:47:46 PM1/30/13
to clo...@googlegroups.com
I think the objective is to make read, read-string, etc. safe. Explicit use of eval is what it is...short of sandboxing, you're opting into all that eval implies.

- Chas

Steve Miner

unread,
Jan 30, 2013, 2:00:30 PM1/30/13
to clo...@googlegroups.com
I would prefer that *read-eval* default to false. In this case, security is more important than backwards compatibility.

However, I want to point out that there is an issue with backwards compatibility, especially for users of *print-dup* (default false). In many cases, with *print-dup* true, the printed representation will use the "#=" notation, which is readable only if *read-eval* is true.

If your code is binding *print-dup*, you probably should be binding *read-eval* explicitly, not depending on the default.


Chas Emerick

unread,
Jan 30, 2013, 5:32:33 PM1/30/13
to clo...@googlegroups.com
On Jan 30, 2013, at 12:23 PM, Michael Fogus wrote:

>> RuntimeException EvalReader not allowed when *read-eval* is false.
>
> The problem is that the second eval gets (<the actual + function> 1 2
> 3) which invokes the right pathway triggering the exception. You can
> trigger the same exception by:
>
> (binding [*read-eval* false] (eval (list + 1 2 3)))

Re-reading this, I'm clearly not grokking something here. Maybe I'm having a slow afternoon; send help. :-P

This obviously ends up running through EvalReader — but why? How is LispReader ever involved at all?

Thanks,

- Chas

Michał Marczyk

unread,
Jan 30, 2013, 5:59:15 PM1/30/13
to clo...@googlegroups.com
I believe the story goes like so:

The eval call here compiles a list of a function object and three
numbers. The function object gets compiled to code which effectively
calls readString on "#=(clojure.core$_PLUS_. )". (It so happens that
print-dup knows how to handle functions; if it didn't, an exception
would be thrown during compilation with the message "Can't embed
object in code, maybe print-dup not defined: ...".) When the compiled
code is executed, readString gets called to reconstruct the function,
and since *read-eval* is false, this fails.

+1 to setting *read-eval* to false by default, by the way.

Cheers,
Michał

>
> Thanks,
>
> - Chas

Michał Marczyk

unread,
Jan 30, 2013, 6:02:17 PM1/30/13
to clo...@googlegroups.com
PS. The relevant part of Compiler.java is the emitValue method of
ObjExpr (or grep for readStringMethod -- I believe this is its only
use in the compiler).

Chas Emerick

unread,
Jan 31, 2013, 8:03:32 PM1/31/13
to clo...@googlegroups.com

On Jan 30, 2013, at 5:59 PM, Michał Marczyk wrote:

> On 30 January 2013 23:32, Chas Emerick <ch...@cemerick.com> wrote:
>> On Jan 30, 2013, at 12:23 PM, Michael Fogus wrote:
>>
>>>> RuntimeException EvalReader not allowed when *read-eval* is false.
>>>
>>> The problem is that the second eval gets (<the actual + function> 1 2
>>> 3) which invokes the right pathway triggering the exception. You can
>>> trigger the same exception by:
>>>
>>> (binding [*read-eval* false] (eval (list + 1 2 3)))
>>
>> Re-reading this, I'm clearly not grokking something here. Maybe I'm having a slow afternoon; send help. :-P
>>
>> This obviously ends up running through EvalReader — but why? How is LispReader ever involved at all?
>
> I believe the story goes like so:
>
> The eval call here compiles a list of a function object and three
> numbers. The function object gets compiled to code which effectively
> calls readString on "#=(clojure.core$_PLUS_. )". (It so happens that
> print-dup knows how to handle functions; if it didn't, an exception
> would be thrown during compilation with the message "Can't embed
> object in code, maybe print-dup not defined: ...".) When the compiled
> code is executed, readString gets called to reconstruct the function,
> and since *read-eval* is false, this fails.

Whoo, sneaky. If only fns carried (most of) the metadata that their originating vars were defined with, print-dup would be able to emit a fully-qualified symbol instead of that bonkers ctor call...I think.

This explains why my plan for a nuclear option for "fixing" *read-eval*'s default doesn't work when outside of a bare `java -cp ... clojure.main` REPL:

https://gist.github.com/4674181

Much of the initialization of the nREPL / Leiningen / Reply toolchain involves evaluating code that's been prn'ed, and there may very well be a couple of nested `eval` usages lurking in there similar to what Fogus raised.

So, getting *read-eval* to a safe default is going to require more than just setting its default to false; all usages of #= in https://github.com/clojure/clojure/blob/master/src/clj/clojure/core_print.clj need to be eliminated. Will be peeking at that next...

- Chas

Chas Emerick

unread,
Feb 1, 2013, 8:04:32 AM2/1/13
to clo...@googlegroups.com
It looks like print-dup is actually significantly relied upon by the compiler when emitting constants (e.g. keyword and symbol literals, namespaces, vars, etc) for generated classes. (There might be other usages that I haven't uncovered yet, but I don't *think* so.) I think that that print-dup usage will need to be replaced with corresponding asm method emits if we are to default *read-eval* to false without introducing eval-related limitations that will appear to nearly all users to be arbitrary and capricious.

Per usual, I'm in over my head around compiler issues, but we'll see what next week brings. I suspect others that have done more compiler hacking than I would have an easier time of it...

Cheers,

- Chas

Chas Emerick

unread,
Feb 1, 2013, 5:31:48 PM2/1/13
to clo...@googlegroups.com
I have added a patch to CLJ-1153 that appears to address the *read-eval* problem:

http://dev.clojure.org/jira/browse/CLJ-1153?focusedCommentId=30523#comment-30523

code on github: https://github.com/cemerick/clojure/commit/1f5c19c07443d2535ede4ff71d23b40c195d617f

artifact on Clojars: [com.cemerick/clojure "1.5.0-SNAPSHOT"]

The Leiningen dependency above is 1.5.0-RC4 + the patch on the ticket. Note that you'll need to set your project's global :exclusions to [org.clojure/clojure] in order for the com.cemerick/clojure artifact to supersede it.

It tests well for me, but needs to be exercised as much as possible. Some have already done so (there's an ongoing discussion on the clojure-dev ML with some initial test experiences: http://groups.google.com/group/clojure-dev/browse_frm/thread/cc6f747919db6c94), but I'm hoping that we can get as many eyes as possible on this — doing both testing as well as code/patch examination — so as to ensure correctness and maximize the chances of 1.5.0 final going out with this vulnerability buttoned up.

Thanks,

- Chas

Baishampayan Ghose

unread,
Feb 1, 2013, 11:10:10 PM2/1/13
to Clojure Group
Just did some testing with our code-base and Clojure 1.5.0-RC4 (with
and without Chas' read-eval patch).

There is definitely something strange going on. Things worked just
fine with 1.5.0-RC4 but with the read-eval patch `lein swank` is
completely broken but more than that, our code is failing to compile
with this weird error -

eval-reader: (clojure.lang.PersistentArrayMap/create {:author "Joe Dev
<j...@helpshift.com>", :doc "Some doc here."})
RuntimeException EvalReader not allowed when *read-eval* is false.
clojure.lang.Util.runtimeException (Util.java:219)

Almost all our namespaces have documentation attached via metadata like this -

(ns ^{:doc "Some doc here."
:author "Joe Dev <j...@helpshift.com>"}
com.helpshift.some.ns
(:require [com.helpshift.other.ns :as chon])
(:use clojure.test
midje.sweet))

FWIW, the file that will fail to compile is random and I couldn't
reproduce this error on a fresh project with just a couple of files.

It's quite clear that the eval-reader is getting used from inside
Clojure and we need to test out the edge cases a bit more.

This is clearly not a low-impact fix, but IMHO we should take the time
and get it right before 1.5.0

Regards,
BG
> --
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Baishampayan Ghose
b.ghose at gmail.com

Chas Emerick

unread,
Feb 2, 2013, 9:13:11 AM2/2/13
to clo...@googlegroups.com
Hi Baishampayan,

I got such errors when I first started working on the patch; they were caused by the compiler using print-dup'd strings to create namespaces instead of emitting bytecode (which the patched build includes). Is it possible that you have both an org.clojure/clojure jar and the patched com.cemerick/clojure jar on your classpath?

FWIW, such metadata happens to exist in some nREPL namespaces, and some of my projects as well, so I presume that that's not the actual problem.

Just out of curiosity, do things work well if you use e.g. inferior-lisp or ritz?

Thanks for testing!

- Chas

Baishampayan Ghose

unread,
Feb 2, 2013, 9:22:00 AM2/2/13
to Clojure Group
I put the canonical clojure artefact in a global exclusions vector in
my project.clj. The classpath doesn't have any duplicate clojure jar
in it. I was testing it out with `lein repl`, since swank-clojure is
broken in different ways.

Regards,
BG

Baishampayan Ghose

unread,
Feb 2, 2013, 9:25:33 AM2/2/13
to Clojure Group
By the way, this is how swank-clojure 1.4.4 is failing to compile with
the patched clojure jar -

Exception in thread "main" java.lang.IllegalArgumentException: No
matching ctor found for class clojure.lang.Compiler$CompilerException,
compiling:(swank/commands/basic.clj:183:24)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6607)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$ThrowExpr$Parser.parse(Compiler.java:2306)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5748)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2679)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5748)
at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2158)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5748)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5179)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3753)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6598)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3575)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6602)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2129)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5748)
at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:6049)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.access$100(Compiler.java:39)
at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:6013)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5748)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5179)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3753)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6598)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.access$100(Compiler.java:39)
at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:531)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6588)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3626)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6602)
at clojure.lang.Compiler.analyze(Compiler.java:6401)
at clojure.lang.Compiler.analyze(Compiler.java:6362)
at clojure.lang.Compiler.compile1(Compiler.java:7185)
at clojure.lang.Compiler.compile(Compiler.java:7255)
at clojure.lang.RT.compile(RT.java:389)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5043.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4992.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:621)
at clojure.core$use.doInvoke(core.clj:5497)
at clojure.lang.RestFn.invoke(RestFn.java:512)
at swank.swank$loading__4935__auto__.invoke(swank.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3460)
at clojure.lang.Compiler.compile1(Compiler.java:7190)
at clojure.lang.Compiler.compile1(Compiler.java:7180)
at clojure.lang.Compiler.compile(Compiler.java:7255)
at clojure.lang.RT.compile(RT.java:389)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5043.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4992.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:621)
at clojure.core$use.doInvoke(core.clj:5497)
at clojure.lang.RestFn.invoke(RestFn.java:805)
at moby.core$loading__4935__auto__.invoke(core.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3460)
at clojure.lang.Compiler.compile1(Compiler.java:7190)
at clojure.lang.Compiler.compile1(Compiler.java:7180)
at clojure.lang.Compiler.compile(Compiler.java:7255)
at clojure.lang.RT.compile(RT.java:389)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5043.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$load_lib$fn__4992.invoke(core.clj:5365)
at clojure.core$load_lib.doInvoke(core.clj:5364)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$load_libs.doInvoke(core.clj:5403)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:619)
at clojure.core$require.doInvoke(core.clj:5486)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at api.lib.server$loading__4935__auto__.invoke(server.clj:1)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3460)
at clojure.lang.Compiler.compile1(Compiler.java:7190)
at clojure.lang.Compiler.compile1(Compiler.java:7180)
at clojure.lang.Compiler.compile(Compiler.java:7255)
at clojure.lang.RT.compile(RT.java:389)
at clojure.lang.RT.load(RT.java:429)
at clojure.lang.RT.load(RT.java:402)
at clojure.core$load$fn__5043.invoke(core.clj:5520)
at clojure.core$load.doInvoke(core.clj:5519)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5326)
at clojure.core$compile$fn__5048.invoke(core.clj:5531)
at clojure.core$compile.invoke(core.clj:5530)
at user$eval7.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6659)
at clojure.lang.Compiler.eval(Compiler.java:6649)
at clojure.lang.Compiler.eval(Compiler.java:6622)
at clojure.core$eval.invoke(core.clj:2852)
at clojure.main$eval_opt.invoke(main.clj:300)
at clojure.main$initialize.invoke(main.clj:319)
at clojure.main$null_opt.invoke(main.clj:354)
at clojure.main$main$fn__6682.invoke(main.clj:432)
at clojure.main$main.doInvoke(main.clj:429)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: No matching ctor found
for class clojure.lang.Compiler$CompilerException
at clojure.lang.Compiler$NewExpr.<init>(Compiler.java:2415)
at clojure.lang.Compiler$NewExpr$Parser.parse(Compiler.java:2502)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6600)
... 167 more

On Sat, Feb 2, 2013 at 7:43 PM, Chas Emerick <ch...@cemerick.com> wrote:

Chas Emerick

unread,
Feb 2, 2013, 11:20:39 AM2/2/13
to clo...@googlegroups.com
Ah, I didn't grok that you were reporting two separate breakages (one in swank, one in your app).

I think the problem is in how the lein-swank plugin sets up dependencies (or, how Leiningen itself applies :exclusions). If you don't have an org.clojure/clojure dependency in your project, then lein-swank will add one, its default (v1.2.1). In this case, I found I did have two clojure jars; my 1.5.0-SNAPSHOT, and [org.clojure/clojure "1.2.1"]. This explains the bizarre message of "No
matching ctor found for class clojure.lang.Compiler$CompilerException". In my verification of swank, I ended up just temporarily swapping the com.cemerick/clojure build in where the official RC4 sits in ~/.m2/repository; once I did that, swank was happy.

I haven't yet been able to duplicate the other fault you saw. If it was really due to namespace metadata, then `lein repl` wouldn't ever start, given clojure.tools.nrepl.server's namespace metadata (https://github.com/clojure/tools.nrepl/blob/master/src/main/clojure/clojure/tools/nrepl/server.clj). I wonder if you could produce a cut-down example that exhibits the issue repeatably?

Thanks,

- Chas

Chas Emerick

unread,
Feb 2, 2013, 11:28:09 AM2/2/13
to clo...@googlegroups.com
One thing that hasn't been mentioned so far is that AOT-compiled classfiles generated using prior builds of Clojure will not load using a build of Clojure that includes a patch like this. Just something to consider for those of you taking the time to test, etc.

- Chas

Chas Emerick

unread,
Feb 9, 2013, 5:10:23 PM2/9/13
to clo...@googlegroups.com
Hi all,

It looks like Rich has selected an approach to addressing *read-eval*, #=, and related issues. The sands may still be shifting a bit, but far less than e.g. earlier this week. With that in mind, I thought it might be helpful to point to three authoritative messages from the clojure-dev ML that describe various relevant changes and additions coming in 1.5.0. The first one contains a summary of the general principles involved, but note that the "default mode" described therein didn't last, as described in the second message:

http://groups.google.com/group/clojure-dev/msg/786c689b596bb6a3
http://groups.google.com/group/clojure-dev/msg/f299efc525f096e2
http://groups.google.com/group/clojure-dev/msg/8b572b8ebaba2ff5

Most relevant to the tactical concern of this thread (the default value of *read-eval* and its implications) is the new ability to set that default via a Java system property.

Hopefully the above satiates anyone yearning for news on this topic until the 1.5.0 changelog is updated to reflect the relevant changes.

Finally, I just wanted to thank everyone, for your attention, energy, enthusiasm, and brilliance. It's an honor to be among you.

Cheers,

- Chas
Reply all
Reply to author
Forward
0 new messages