内存安全绝对主义者

Lobsters Hottest 新闻

摘要

本文批评了编程语言辩论中的内存安全绝对主义,认为像 Fil-C 这样的新方法也有权衡,而将 Rust 视为不安全忽略了实际好处。

<p><a href="https://lobste.rs/s/x7jtkt/memory_safety_absolutists">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/25 22:08

# 内存安全绝对主义者 来源:https://itsallaboutthebit.com/memory-safety-absolutists/ 作者:Piotr Sarnacki (https://hachyderm.io/@drogus) 发表于 2026 年 7 月 28 日 看到这篇文章的标题时,我敢打赌有些人脑子里蹦出的第一个念头是“Rust 开发者!”。这种联想并非空穴来风。Rust 开发者往往对内存安全充满热情。其中一部分,我确信,可能源自经典的语言战争心态:我的语言比你的好,原因如下。不过,我希望大多数声称关心内存安全的 Rust 开发者是真心希望让软件更安全,而不是仅仅为了批评与 Rust 竞争的语言。 出人意料的是,这篇文章并非关于 Rust 开发者。 直到最近,大多数关于内存安全的讨论都有一个相对简单的基础——至少是在考虑非垃圾回收(GC)的系统编程语言时,比如 C、C++、Zig 和 Rust。Rust 的目标是不允许编译可能引入内存安全问题的程序(代价是偶尔会阻止一些本可安全的程序),同时通过 `unsafe` 提供逃生舱,允许对裸指针进行解引用等操作。而 C 和其他语言则将确保内存安全的责任留给程序员。语言提供的帮助程度不同,例如 C++ 中有 RAII 和智能指针,Zig 中有 `defer`,但大多数情况下,没有任何机制能阻止你违反内存访问规则。 如今的情况有所不同,出现了一种让 C、C++ 以及未来可能的 Zig 代码实现内存安全的新方法:Fil-C (https://fil-c.org/)。使用 Fil-C 编译的 C 和 C++ 代码在发生无效内存访问(如越界访问或释放后使用)时会 panic。它通过结合垃圾回收和 InvisiCaps(一种追踪指针可访问内存的方式)来实现这一点。Zig 的作者最近宣布了一种受 Fil-C 启发的 Zig 新编译模式 (https://codeberg.org/ziglang/zig/issues/36237)。Fil-C 是一个非常有趣的项目,我真诚希望它能成功,并希望至少一些流行的 C 和 C++ 项目能提供 Fil-C 编译的版本。 在理想世界中,关心内存安全的 Rust 程序员和 C/C++/Zig 程序员都会高兴看到有更多方法能最小化内存安全漏洞。但可惜,我们并不生活在理想世界中,我总感觉最近对 Rust 的很多批评是虚伪的。如果你读过 Fil-C 作者在 Twitter 上的观点 (https://x.com/filpizlo),很明显他不喜欢 Rust,我曾看到他声称 Rust 是一种内存不安全的语言,因为使用 `unsafe` 时可以绕过 Rust 的一些保障。Zig 的作者 Andrew Kelley 似乎也有类似立场,这体现在那个“fil 编译模式”的 issue 标题中:“引入一种受 Fil-C 启发的、真正内存安全(不同于 Rust)的编译模式”。意思是:Rust 不安全,只有 Fil-C 或 Zig 的“fil”编译模式才能解决内存安全相关的漏洞。 在与 Rust 和 Fil-C 相关的讨论中,我经常看到类似这样的说法:“如果 Rust 的家伙们真的关心内存安全,他们就会推广 Fil-C,然后放弃 Rust,因为 Fil-C 更安全;否则他们只是关心他们那闪亮的新语言,而不是内存安全。”这包括 Fil-C 作者本人。我不确定 Andrew Kelley 是否如此,但我之前提到的那个 issue 标题感觉非常接近。这类论点,在我看来,忽视了现实,感觉像是狂热和邪教般的行为——而 Rust 开发者常常被指责的正是这些。 如果 Fil-C 是一个零代价的直接替代品,我或许会部分同意这种观点,但它是有代价的:它与非 Fil-C 编译的程序 ABI 不兼容,某些情况下可能慢几倍,并且引入了垃圾回收。这些对某些程序来说并非不可逾越的障碍。你日常使用的很多程序即使慢几倍,你也不会注意到。很多程序也不动态链接任何东西,所以 ABI 兼容性无所谓。但并非每个软件程序都是简单的工具。有许多流行项目,垃圾回收和 ABI 不兼容是个问题,它们永远不可能使用像 Fil-C 这样的技术,至少不是当前的形式。关键在于,那些无法使用 Fil-C 的程序往往非常适合 Rust。 但 Rust 不安全,不是吗?毕竟它有 `unsafe`!如果你要这么严格,或者说,如果你是一个内存安全绝对主义者,那对你来说可能确实如此。我——也希望大家——更务实一些。关于 Rust 在实践中的安全性,数据并不多,但据我所知,Rust 软件中还没有多少可利用的内存安全漏洞,而且有一些大型项目提供了数据,比如 Android 中的 500 多万行代码 (https://blog.google/security/rust-in-android-move-fast-fix-things/#:~:text=With%20roughly%205%20million%20lines,1%20million%20lines%20(MLOC).): > 在 Android 平台中大约有 500 万行 Rust 代码,发现了一个潜在的内存安全漏洞(并在发布前修复),我们估计 Rust 的漏洞密度为每 100 万行代码 0.2 个漏洞。 > > 我们的 C 和 C++ 历史数据显示,漏洞密度接近每 100 万行代码 1000 个内存安全漏洞。我们的 Rust 代码目前的漏洞密度低了数个数量级:减少了超过 1000 倍。 我相信这些数字在其他项目中会有所不同,但我认为到目前为止已经可以确认,在实践中 Rust 能最大程度降低引入内存安全问题的风险。 如果你可以选择一项技术:要么在 100% 的程序中防止 99.9% 的问题,要么在 90% 的程序中防止 100% 的问题,你会选哪个?我不知道真实数字是多少,但你明白我的意思。幸运的是,我们不必二选一——这与某些人所声称的相反。我希望那些用 C/C++/Zig 编写、能够接受某些代价的项目,能够提供 Fil-C 编译的二进制版本;而那些无法接受代价的软件,则可以用那些能完全或大部分消除引入内存安全漏洞风险的语言来编写。 而且我也认为,即使你可以使用像 Go 或 Fil-C 这样的垃圾回收语言,使用 Rust 也完全没问题。内存安全绝对主义者会告诉你这是不可接受的,尽管他们中有些人似乎只在涉及 Rust 时才坚持内存安全绝对主义,而对 C、C++ 或 Zig 却不那么坚持——真搞不懂。问题是,那些也可以用垃圾回收语言编写的程序,往往根本不需要 `unsafe`,而需要 `unsafe` 的程序通常也无法使用垃圾回收。根据我的经验,那些不以完全狂热的态度解决问题的人,往往会权衡利弊。对他们中的许多人来说,遇到严重内存安全问题的极小风险,被其他语言保障(比如数据竞争预防)和语言特性所抵消。更重要的是,还记得每百万行代码 1000 个内存安全漏洞吗?有了 Fil-C,它们会变成崩溃。这仍然比引入安全漏洞要好,但需要修复的崩溃数量相当多。如果我们是在担心相对罕见的问题,那么或许应该指出,过去确实存在因攻击者能够使程序崩溃而引发的安全漏洞。 最后我想说,如果有人如此关心内存安全,以至于连 Rust 每百万行代码 0.2 个漏洞都无法接受,那么我希望他们也会同样(甚至更多)批评那些编译“YOLO”式 C/C++ 以及非 fil 模式 Zig 的人。毕竟,如果你真的这么强烈地关心内存安全,甚至认为 Rust 都不够安全,那你肯定也不希望别人使用更不安全的替代方案,对吧? --- 如果你喜欢这篇文章,请考虑在 Twitter 上关注我 (http://twitter.com/drogus)。

相似文章

实用内存安全

Lobsters Hottest

文章讨论了最近通过 Fil-C 提出的 Zig 内存安全方案,比较了 Fil-C 与 Rust 对内存安全的定义,并主张内存安全是一个具有实用定义的频谱,同时使用了一个 Fil-C 仍然不安全的具体示例。

内存安全是生死攸关的问题

Lobsters Hottest

作者认为,内存不安全的开源软件极易受到即将到来的人工智能漏洞查找代理的攻击,这使内存安全成为道德义务,并且Rust必须作为领先且零开销的内存安全语言取得成功。