Skip to content

Script parameters lead to unbound system variables in Clojure #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kephale opened this issue Jun 23, 2017 · 1 comment
Open

Script parameters lead to unbound system variables in Clojure #5

kephale opened this issue Jun 23, 2017 · 1 comment

Comments

@kephale
Copy link
Contributor

kephale commented Jun 23, 2017

This Clojure script works:

(println "hello world")

This Clojure script works:

#@String name
#@output String output

(def output (str name "J"))

This Clojure script does not work:

#@String name

(println "hello world")

Throwing the following error:

[ERROR] Module threw exception
java.lang.NullPointerException
	at java.io.Writer.<init>(Writer.java:88)
	at java.io.PrintWriter.<init>(PrintWriter.java:113)
	at java.io.PrintWriter.<init>(PrintWriter.java:100)
	at clojure.lang.RT.errPrintWriter(RT.java:271)
	at clojure.lang.Namespace.warnOrFailOnReplace(Namespace.java:90)
	at clojure.lang.Namespace.intern(Namespace.java:72)
	at clojure.lang.Var.intern(Var.java:158)
	at clojure.lang.RT.var(RT.java:343)
	at org.scijava.plugins.scripting.clojure.ClojureBindings.get(ClojureBindings.java:105)
	at org.scijava.plugins.scripting.clojure.ClojureBindings.put(ClojureBindings.java:120)
	at org.scijava.script.AbstractScriptEngine.put(AbstractScriptEngine.java:99)
	at org.scijava.script.ScriptModule.run(ScriptModule.java:148)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:167)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:237)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)
java.util.concurrent.ExecutionException: java.lang.NullPointerException
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at org.scijava.ui.swing.script.TextEditor.evalScript(TextEditor.java:2348)
	at org.scijava.ui.swing.script.TextEditor.access$1000(TextEditor.java:149)
	at org.scijava.ui.swing.script.TextEditor$20.execute(TextEditor.java:1939)
	at org.scijava.ui.swing.script.TextEditor$Executer$1.run(TextEditor.java:1751)
Caused by: java.lang.NullPointerException
	at java.io.Writer.<init>(Writer.java:88)
	at java.io.PrintWriter.<init>(PrintWriter.java:113)
	at java.io.PrintWriter.<init>(PrintWriter.java:100)
	at clojure.lang.RT.errPrintWriter(RT.java:271)
	at clojure.lang.Namespace.warnOrFailOnReplace(Namespace.java:90)
	at clojure.lang.Namespace.intern(Namespace.java:72)
	at clojure.lang.Var.intern(Var.java:158)
	at clojure.lang.RT.var(RT.java:343)
	at org.scijava.plugins.scripting.clojure.ClojureBindings.get(ClojureBindings.java:105)
	at org.scijava.plugins.scripting.clojure.ClojureBindings.put(ClojureBindings.java:120)
	at org.scijava.script.AbstractScriptEngine.put(AbstractScriptEngine.java:99)
	at org.scijava.script.ScriptModule.run(ScriptModule.java:148)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:167)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:237)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)

Note that Clojure's println works by binding System.out to *out*, and # indicates the beginning of a reader macro in Clojure. The suspicion is that the # is slipping through and messing with the establishment of the user namespace in Clojure.

@ctrueden
Copy link
Member

The following script works:

#@String myName
(println "hello world")

So the problem is specifically having a parameter called name here, I think.

Note the following warning which is emitted to the console for your first script:

WARNING: name already refers to: #'clojure.core/name in namespace: user, being replaced by: #'user/name

The issue is not that the clojure interpreter is receiving rogue # symbols, but merely that such variables are being injected into the bindings.

I started trying to debug by writing a Groovy script (it was an excuse to name a file clojure.groovy 😜 ):

#@ScriptService scriptService

// NB: \n avoids #@ parameter harvesting in the containing script.
script = """
\n#@String myName
(println "hello world")
"""

lang = scriptService.getLanguageByName("clojure")
println("clojure language = $lang")
engine = lang.getScriptEngine()
println("clojure engine = $engine")
//engine.put("myName", "Curtis")
engine.put("name, "Curtis")
//NB: Asking for the Bindings and putting there instead has the same effect:
//bindings = engine.getBindings(javax.script.ScriptContext.ENGINE_SCOPE)
//bindings.put("myName", "Curtis")
//bindings.put("name", "Curtis")
result = engine.eval(script)
println("result = " + result)

I was hoping to see that injecting such a variable directly into the bindings would have the same problem as the one above, but actually in that case I have different problems:

java.lang.RuntimeException: Reader tag must be a symbol
	at clojure.lang.LispReader$CtorReader.invoke(LispReader.java:1221)
	at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:684)
	at clojure.lang.LispReader.read(LispReader.java:263)
	at clojure.lang.LispReader.read(LispReader.java:196)
	at clojure.lang.LispReader.read(LispReader.java:190)
	at org.scijava.plugins.scripting.clojure.ClojureScriptEngine.eval(ClojureScriptEngine.java:86)
	at org.scijava.plugins.scripting.clojure.ClojureScriptEngine.eval(ClojureScriptEngine.java:63)
	at javax.script.ScriptEngine$eval$1.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
	at Script22.run(Script22.groovy:15)
	at org.scijava.plugins.scripting.groovy.GroovyScriptEngine.eval(GroovyScriptEngine.java:303)
	at org.scijava.plugins.scripting.groovy.GroovyScriptEngine.eval(GroovyScriptEngine.java:122)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at org.scijava.script.ScriptModule.run(ScriptModule.java:159)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:167)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:237)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)

Or with "name" instead of "myName":

java.lang.NullPointerException
	at java.io.Writer.<init>(Writer.java:88)
	at java.io.PrintWriter.<init>(PrintWriter.java:113)
	at java.io.PrintWriter.<init>(PrintWriter.java:100)
	at clojure.lang.RT.errPrintWriter(RT.java:271)
	at clojure.lang.Namespace.warnOrFailOnReplace(Namespace.java:90)
	at clojure.lang.Namespace.intern(Namespace.java:72)
	at clojure.lang.Var.intern(Var.java:158)
	at clojure.lang.RT.var(RT.java:343)
	at org.scijava.plugins.scripting.clojure.ClojureBindings.get(ClojureBindings.java:105)
	at org.scijava.plugins.scripting.clojure.ClojureBindings.put(ClojureBindings.java:120)
	at org.scijava.script.AbstractScriptEngine.put(AbstractScriptEngine.java:99)
	at javax.script.ScriptEngine$put.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
	at Script25.run(Script25.groovy:14)
	at org.scijava.plugins.scripting.groovy.GroovyScriptEngine.eval(GroovyScriptEngine.java:303)
	at org.scijava.plugins.scripting.groovy.GroovyScriptEngine.eval(GroovyScriptEngine.java:122)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at org.scijava.script.ScriptModule.run(ScriptModule.java:159)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:167)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:126)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:65)
	at org.scijava.thread.DefaultThreadService$3.call(DefaultThreadService.java:237)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)

I haven't looked at this code since last October (see commit history), so I basically completely forgot how anything works. And it is after midnight now, so I think I'll continue investigations some other day.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants