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

欢迎!有关如何使用这个网站的更多信息,请参阅 关于 页面。

0 投票
编译器

编译引用未加载(或未初始化)类的函数会触发其初始化静态代码。当初始化静态代码加载 Clojure 代码时,某些常量(我认为是源代码)会泄漏到正在编译的函数的常量池中。

这阻止了在有些环境中(Rational)CCW 的工作,因为结果函数的静态初始化超过了 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 投票

评论者:bronsa

我对 lein compile 在做什么完全没有任何头绪,但我想出了问题所在。
更新过的补丁在 eval 中只当已经绑定时才绑定适当的 vars。

0 投票

评论人: alexmiller

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

0 投票

评论者:bronsa

有道理,已更新补丁以使用transient映射

0 投票

评论人: michaelblume

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

0 投票

评论者:bronsa

我将不得不考虑如何重现该缺陷,它不是一个简单的场景。
涉及到从评估环境中编译一个命名空间。

0 投票

评论人: laurentpetit

这个问题还有机会出现在1.7版本中吗?

0 投票

评论人: alexmiller

我本来就没有这个计划 - 这对你有什么影响吗?

0 投票

评论人: laurentpetit

影响是,我需要为CCW使用Clojure的修补版本。
虽然目前跟踪Clojure的主要分支并定期进行变基或重新应用补丁并不那么困难,但这仍然是一种浪费。

0 投票

评论人: alexmiller

在我们进入RC之前,我将检查Rich是否可以在1.7之前对其进行筛选。

0 投票

评论人: alexmiller

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

0 投票

评论人: laurentpetit

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

0 投票

评论人: alexmiller

是哪一个?

0 投票

评论人: laurentpetit

我想你可能的先前评论与clj-1620-v5.patch有关,但在描述的末尾有如下一行

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

0 投票

评论人: alexmiller

这些补丁就引入的变化而言是等效的;它们只是在差分上下文方面有所不同。

...