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
"Some doc"
[]
"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 投票
by

评论由:bronsa 发布

我仍然完全没有头绪关于lein compile具体在做啥,但我已经找到了问题所在。
更新后的补丁仅在已绑定的变量上才(在eval中)绑定适当的变量。

0 投票
by

评论者:alexmiller

使用transients在绑定映射现在是否值得?

0 投票
by

评论由:bronsa 发布

有道理,已将补丁更新为使用transient映射。

0 投票
by

评论者:michaelblume

我们能否添加一个测试,该测试在v2补丁存在时会失败?最好是与CLJ-1544补丁独立的?我可以尝试自己编写一个,但我不太熟悉Clojure编译器的内部结构。

0 投票
by

评论由:bronsa 发布

我必须想想如何重现这个错误,它不是一个简单的场景。
它涉及从计算过的环境中编译一个命名空间。

0 投票
by

评论者:laurentpetit

嘿,这个 issue 有没有可能覆盖到1.7版本?

0 投票
by

评论者:alexmiller

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

0 投票

评论者:laurentpetit

影响是,我需要为CCW使用Clojure的修复版本。
虽然目前跟踪clojure的主要分支并定期在此上重新基或重新应用补丁不容易,但这仍然是一种浪费时间的做法。

0 投票

评论者:alexmiller

在我们推出候选版本之前,我将与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

这些补丁在引入的更改方面是等效的;它们只是在差异上下文方面有所不同。

...