在 Rust 借用检查器中发现的 11 年陈旧不健全性漏洞

Rust 的借用检查器中发现了一个已有 11 年之久的健全性漏洞:涉及生命周期和自定义 `Drop` 实现的看似普通代码会被错误接受,从而允许引用活得比它所指向的数据更久。评论者分析了这如何违反 Rust 对内存安全的核心承诺,强调这属于编译器实现错误而非语言类型系统本身的缺陷,并指出它似乎需要一个刻意构造的析构函数才能转化为实际利用。此事也引发了更广泛的争论:与 C 相比 Rust 到底有多“安全”、任何类型系统或形式化证明的边界在哪里,以及包括 AI 在内的工具在发现此类细微编译器 bug 方面扮演何种角色。

漏洞性质

  • 借用检查器中围绕 T: 'static 和 Drop 的不健全性。
  • 最小示例:一个带有 Q<T: 'static>(Option<T>) 的泛型结构体,以及同样受 'static 约束的 Drop 实现。
  • 编译器错误地允许在 Q 中存储非 'static 引用(例如带有栈生命周期的 &l),而 Q 本应只包含 'static 数据。
  • 然后析构函数可能把它当作 'static 来处理,例如将其藏进全局变量中,从而导致 use-after-free。

为什么一直没有被发现

  • 触发模式被认为不寻常:需要一个自定义 Drop,并且生命周期约束以特定方式组合。
  • 对“正常”自定义 Drop 的普遍程度存在争论:有人说很少见,也有人说很常见,尤其是在 FFI 场景中;但这种精确模式很少见。
  • 许多无效的生命周期程序可能不会显式崩溃,因此即使漏洞被触发,也未必会出现明显故障。

安全保证、不健全性与 UB

  • 说明:
    • 不健全性 = 安全 Rust 由于编译器/类型检查器缺陷而导致 UB。
    • 规范中的 UB = 用户越出了明确定义的行为范围。
  • 这个漏洞在编译器中,而不在 Rust 预期的生命周期规则中;修复方法是拒绝这类代码。
  • 有人指出仍有许多未解决的不健全性问题;也有人强调修复可以在补丁版本中发布,而受影响的代码从未是“有效的 Rust”。

与 C 和其他语言的比较

  • 有人借此认为 Rust 的安全宣传被夸大了,或者会给人一种虚假的安全感。
  • 也有人反驳说,C/C++ 既有编译器 bug,又有普遍存在的语言级 UB,因此 Rust 仍然是安全性上的重大进步。
  • 讨论还指出,没有任何语言能做到绝对安全;目标是让某些 bug 类别变得不可能,或极其罕见。

形式化方法与 AI

  • 提到了当前对 Rust 或其子集进行形式化规范/证明的持续努力。
  • 也承认即使是证明助手、规范和底层数学本身也可能出错,因此不可能有绝对保证。
  • 有人认为 AI/LLM 是通过 fuzzing/搜索编译器来发现此类漏洞的有前景工具;也有人对此持怀疑或对 AI 炒作感到疲惫。

社区与社会动态

  • 有人抱怨 Rust 传教式推广,以及对其他语言的贬低;也有人为官方表述更为克制而辩护。
  • 关于对单个漏洞的过度反应也有元讨论:有人呼吁保持视角——这是真实但狭窄的缺陷,而不是 Rust 模型整体失败。