一份补丁能编译通过,等于它把漏洞修好了——2609.26749 花了五个实验说明这两件事没关系
编译率作为漏洞修复的进展代理指标,论文用五个对照实验论证它对单函数修复不可靠。帖子把五条都译了,但没译的是这五个实验的规模——203 个函数、3 个 350M–6.7B 的模型、9,135 个补丁。我核完发现,问题最狠的地方不在"编译率不可信",而在"它连自己的分母都不可信"。
一、最反直觉的一格:参数量最小的模型编译率最高
| 模型 | 参数量 | 编译率 | CodeBLEU |
|---|---|---|---|
| CodeGen-350M-multi | 350M | 5.45% [3.51, 7.75] | 0.463 |
| DeepSeek-Coder-1.3B | 1.3B | 3.45% [1.38, 6.04] | 0.662 |
| DeepSeek-Coder-6.7B | 6.7B | 3.32% [1.22, 5.88] | 0.675 |
论文很诚实地补了一句:三个置信区间全部重叠,编译率根本没区分开这三个模型。
【直引】作者自陈的限制里还有一条:"3%–5.5% 的编译率可能反映模型本身较弱。" 论文的反驳是:约 64% 的失败归因于独立于模型质量的评测设置,且这个比例在参数规模相差近 20 倍的模型间几乎不变。但作者同时明确表示,不能排除更强或 instruction-tuned 的模型会表现出不同的 metric failure modes。
二、64% 到底指什么——分母最容易读错的一格
帖里写"约 64% 编译失败不可归因于模型"。这个表述容易被读成"64% 的补丁编译失败"。
原文的分母是各模型自身的编译失败总数:
| 失败原因 | 350M | 1.3B | 6.7B |
|---|---|---|---|
| 模型生成畸形 C | 19.4% | 18.2% | 17.9% |
| 模型生成非代码输出 | 0.5% | 0.0% | 0.1% |
| 缺项目上下文 | 45.1% | 44.0% | 43.7% |
| harness/工具链可修 | 4.1% | 2.4% | 2.5% |
| Big-Vul 返回类型被预处理删除 | 14.9% | 18.3% | 18.7% |
| 其他 | 16.0% | 17.1% | 17.0% |
| 非模型合计 | 64.1% | 64.7% | 64.9% |
把这两行加起来就明白了:45.1% + 14.9% = 60%,是"缺上下文"和"输入签名本身被损坏"。后者尤其扎眼——论文说,在"看不到函数返回类型"的失败中,96%–100% 的原始 func_before 已经被 Big-Vul 的预处理删掉了返回类型。
【直引】换句话说:模型是在忠实复制一个已经损坏的输入签名,然后被编译器骂。这不是模型能力问题,也不是提示工程能解决的。
三、换个编译标准,编译率变 1.8–2.7 倍,且零回退
同一批补丁,模型不重新生成,只改一个 C 标准参数:
| 模型 | 默认(C23) | gnu17 | gnu89 | 倍数 |
|---|---|---|---|---|
| CodeGen-350M | 5.45% | 5.45% | 10.25% | 1.88× |
| DeepSeek-1.3B | 3.45% | 3.45% | 8.83% | 2.56× |
| DeepSeek-6.7B | 3.32% | 3.32% | 8.90% | 2.68× |
gnu17 跟默认完全一样;只有掉到 gnu89 才涨——因为 gnu89 接受现代 C 里非法的隐式 int 返回类型和隐式声明函数,而这恰好跟上一格那个"返回类型被删"的问题对上了。【直引】论文补了一条机制细节:GCC 对路由到 g++ 的 C++ 候选会忽略 C 标准参数,所以这个效应主要来自 C 候选。
最有说服力的是"零回退":没有任何一个补丁在 gnu89 下从"能编译"变成"不能编译"。只放宽标准就能捞回一倍的补丁,而一个都没弄坏。
四、CodeBLEU 那格我建议单独看
把未修改的漏洞函数原样当候选:
| 候选 | whole-function CodeBLEU | diff_F1 |
|---|---|---|
| 原样复制输入 | 0.775 | 0.000 |
| CodeGen-350M | 0.463 | 0.281 |
| DeepSeek-1.3B | 0.662 | 0.235 |
| DeepSeek-6.7B | 0.675 | 0.211 |
有意思的是模型自己有多少是真没改:350M 7%、1.3B 26%、6.7B 27%。参数量小的模型反而更倾向于输出原样。
而 diff_F1 给原样复制恰好 0.000。
五、diff_F1 不是银弹,论文自己把软肋摊开了
论文主动列了失败案例:
| 合成补丁 | diff_F1 |
|---|---|
| 原样复制 | 0.000 |
整个函数塞进 #if 0 | 0.027 |
| 空函数体加占位注释 | 0.175 |
函数体只 return 0 | 0.222 |
#if 0 是近零分。但——只包装部分函数体的 #if 0 得 0.48,14 个人工检查出的退化补丁分数落在 0.08–0.48。论文给的机制解释很实在:diff_F1 同时算删除侧和新增侧,模型大量删代码的时候,也可能"命中"开发者当初也删过的行,白拿分。
所以作者把它定位成"进入 execution-based 分析前的廉价筛选",并且明说"it is not a repair-quality metric"。这几句限定语是全篇最诚实的部分。
【直引】还有一条我很少在论文里看到:论文没有做执行验证。没有跑测试,没有跑 PoC exploit,没有验证修复后是否保持原有行为,也没做人工标注。Semgrep 被考虑过但没当成 oracle——4 个退化输出无法解析,其余 9,131 个补丁(含全部 372 个可编译补丁)全无发现。
所以这篇的边界很清楚:它证明了"编译率不可信",没有证明"该用什么替代"。
下一根钉子:作者列的五条后续方向里,第一条是修改 diff_F1 取消删除侧奖励。这一格最好验证——因为它现在有现成数据:那 14 个退化补丁的分数(0.08–0.48)如果只算新增行会掉到多少,292 个正常补丁又会掉多少。掉得不对称,这个指标就能救。另一根:把 350M 到 6.7B 换成 instruction-tuned 模型重跑——作者自己点名的最大不确定性。