Vi.*_*Vi. 8 clojure s-expression
(def evil-code (str "(" (slurp "/mnt/src/git/clj/clojure/src/clj/clojure/core.clj") ")" ))
(def r (read-string evil-code ))
Run Code Online (Sandbox Code Playgroud)
工作,但不安全
(def r (clojure.edn/read-string evil-code))
RuntimeException Map literal must contain an even number of forms clojure.lang.Util.runtimeException (Util.java:219)
Run Code Online (Sandbox Code Playgroud)
不起作用......
如何安全地阅读Clojure代码(将所有'#s本身作为自己的东西)保存到树中?想象一下,Clojure防病毒软件希望扫描代码中的威胁,并希望使用数据结构,而不是使用纯文本.
首先,您永远不应该直接从不受信任的数据源读取 clojure 代码。您应该使用 EDN 或其他序列化格式。
话虽这么说,从 Clojure 1.5 开始,有一种安全的方法可以读取字符串而不需要评估它们。在使用 read-string 之前,您应该将read-eval var 绑定到 false。在 Clojure 1.4 及更早版本中,这可能会因调用 java 构造函数而产生副作用。这些问题现已得到解决。
这是一些示例代码:
(defn read-string-safely [s]
(binding [*read-eval* false]
(read-string s)))
(read-string-safely "#=(eval (def x 3))")
=> RuntimeException EvalReader not allowed when *read-eval* is false. clojure.lang.Util.runtimeException (Util.java:219)
(read-string-safely "(def x 3)")
=> (def x 3)
(read-string-safely "#java.io.FileWriter[\"precious-file.txt\"]")
=> RuntimeException Record construction syntax can only be used when *read-eval* == true clojure.lang.Util.runtimeException (Util.java:219)
Run Code Online (Sandbox Code Playgroud)
关于阅读器宏
调度宏 (#) 和标记文字在读取时调用。Clojure 数据中没有它们的表示,因为到那时这些结构都已被处理。据我所知,没有构建方法来生成 Clojure 代码的语法树。
您将必须使用外部解析器来保留该信息。您可以使用自己的自定义解析器,也可以使用 Instaparse 和 ANTLR 等解析器生成器。可能很难找到这两个库的完整 Clojure 语法,但您可以扩展其中一个 EDN 语法以包含其他 Clojure 形式。快速谷歌揭示了Clojure 语法的 ANTLR 语法,如果需要,您可以更改它以支持缺少的结构。
还有Sjacket,一个为 Clojure 工具制作的库,需要保留有关源代码本身的信息。这似乎很适合你想做的事情,但我个人没有任何经验。从测试来看,它的解析器确实支持读取器宏。