2024 Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面了解如何工作的更多信息。

0 投票
编译器

编译引用未加载(或未初始化)类的函数会触发其初始化静态代码。当初始化静态代码加载Clojure代码时,一些常量(可能是源代码)会泄露到编译中的函数的常量池中。

这导致CCW在某些环境(比如Rational)中无法工作,因为结果函数的静态初始化大于64K。

重现步骤

加载leak.main命名空间,并运行注释中的代码:第一个函数具有15个额外的字段,尽管它与第二个函数相同。

`
(ns leak.main)

(defn first-to-load [])
leak.Klass/foo)

(defn second-to-load [])
leak.Klass/foo)

(comment
=> (map (comp count #(.getFields %) class) [first-to-load second-to-load])
(16 1)
)
`

`
package leak;

import clojure.lang.IFn;
import clojure.lang.RT;
import clojure.lang.Symbol;

public class Klass {
static {

RT.var("clojure.core", "require").invoke(Symbol.intern("leak.leaky"));

}
public static IFn foo = RT.var("leak.leaky", "foo");
}
`

`
(ns leak.leaky)

(defn foo
"一些文档"
[]
"hello")

(def unrelated 42)
`

https://gist.github.com/cgrand/5dcb6fe5b269aecc6a5b#file-main-clj-L10

补丁: clj-1620-v5.patch

33 答案

0 投票

评论由:bronsa 提出

同时,Ghadi 是对的,实际上用 (:foo {}) 替换 thunk-fail.core 的整个体就足够了。

看起来问题出在AOT(重新)编译顶层关键字查找位置,我的猜测是,由于某种原因,这个补丁阻碍了 __init 静态初始化器的正确生成。

0 投票

评论由:bronsa 提出

我对lein compile做了什么一无所知,但已经找到了问题所在。
更新的补丁(在eval中)只绑定适当的变量,当这些变量已经被绑定时。

0 投票

评论者:alexmiller

现在使用绑定映射的transients是否有意义?

0 投票

评论由:bronsa 提出

这样做是有意义的,补丁已更新为使用短暂映射。

0 投票

评论者:michaelblume

我们可以添加一个测试来检测v2补丁存在时的失败情况吗?最好是不依赖于CLJ-1544补丁?我自己也可以尝试编写一个,但我不太熟悉Clojure编译器的内部机制。

0 投票

评论由:bronsa 提出

我需要考虑一种方法来重现该错误,这不是一个简单的重现场景。
这涉及从eval上下文编译一个名称空间。

0 投票

评论者:laurentpetit

你好,还有机会让这个问题解决到1.7版本吗?

0 投票

评论者:alexmiller

本来没有打算这么做 - 对你有什么影响吗?

0 投票

评论者:laurentpetit

影响是我需要使用CCW的Clojure修补版本。
虽然目前跟踪Clojure的主要分支并定期重新合并或重新应用补丁并不难,但这仍然是一种时间浪费。

0 投票

评论者:alexmiller

在我们到达RC之前,我将检查Rich是否可以在1.7之前过滤。

0 投票

评论者:alexmiller

与v4补丁相同,但具有更多的差异上下文。

0 投票

评论者:laurentpetit

在我看来,补丁字段中提到的文件不是正确的文件。

0 投票

评论者:alexmiller

哪一个呢?

0 投票

评论者:laurentpetit

我认为你之前的评论与clj-1620-v5.patch相关,但描述的末尾有以下一行

补丁:0001-CLJ-1620-avoid-constants-leak-in-static-initalizer-v4.patch

0 投票

评论者:alexmiller

这些补丁在引入的更改方面是等价的;它们只是在 diff 上下文量上有差异。

...