Rust 与 C/C++ 在内存安全 CVE 方面有何不同

Rust、未定义行为和 unsafe

  • 有人认为,即使你的 crate 里没有直接使用 unsafe,Rust 中也可能出现 UB:例如通过 no_std、语言健全性漏洞、依赖项或标准库中的 UB,或者编译器/LLVM bug。
  • 也有人强调 Rust 的模型:UB 必须源自某个地方的 unsafe(包括依赖项或 std 里的 unsafe);其好处在于 unsafe 是局部化的、可审查的。

整数溢出语义

  • 关于 Rust 的“调试版 panic、发布版回绕”行为存在争议。
  • 批评者说,这两种行为使溢出在实践中几乎和 UB 一样不可靠,并希望溢出始终 panic。
  • 另一些人强调这属于实现定义,而不是 UB:行为是有界且可配置的(overflow-checks = true),不同于 C/C++ 的 UB,后者可能导致极端的错误优化。

如何解读 Rust 的 CVE

  • Rust 库往往把任何可能导致 UB 的误用都视为 CVE,即使实际利用不太现实。
  • C/C++ 生态很少把这类问题归类为 CVE,因此单看“CVE 数量”被视为衡量语言安全性的误导性指标。
  • 有人担心这可能进一步扩展到把 panic 也当作 DoS 漏洞;也有人认为这是重视正确性的一种文化体现。

内存安全漏洞的普遍性与重要性

  • 一位评论者声称,内存漏洞只占“平均”漏洞中的很小一部分;也有人反驳这一点,并引用线程内的数据称内存安全问题主导了高影响力的 0-day。
  • 讨论还包括:将大型代码库迁移到 Rust 是否是过度优化,还是对高价值、被频繁攻击的软件(浏览器、操作系统组件、Android)而言是合理的。

Rust 与现代 C++ 的安全策略

  • 一方认为,现代 C++ 加上加固库、sanitizer 和编程规范,如果一致使用,基本可以解决内存 bug。
  • 反方观点:
    • 在实践中,许多大型 C/C++ 代码库仍然不安全(Android、Chromium、系统库)。
    • Rust 的安全性是默认的;而在 C++ 中,安全往往需要显式选择、严格纪律,以及团队在交付压力下经常放松的工具链。
    • 现实中的报告(例如 Android)被引用为证据,说明与遗留 C/C++ 代码相比,Rust 能显著减少内存漏洞。

空值、断言与契约

  • 讨论围绕 curl_getenv 之类的函数,以及是否应对空输入进行断言。
  • 有人主张广泛使用前置条件检查;也有人认为在 C 中这会变得冗长,并且往往会退化为“反正空指针解引用时崩溃”。
  • Rust 的 Option<T> 和不可为 null 的引用被拿来对比:API 必须明确选择接受 None,误用会导致带有清晰回溯的 panic,而不是 UB。

性能与采用趋势

  • 像 Ladybird 的 HTML 解析器重写这样的例子显示,Rust 可以在相同或更好的性能下替代 C++。
  • 讨论速度提升究竟来自 Rust 本身,还是来自重写过程中的重新设计机会。
  • 在一些领域(浏览器、内核)里,C 和 C++ 被认为正在失去阵地,不过许多领域(HPC、HFT、受标准驱动的技术栈)仍然围绕 C/C++ 运转。

Rust 的复杂性与依赖担忧

  • 批评者强调 Rust 概念上的复杂性(所有权、生命周期、高级类型),以及为了满足借用检查器而花费在类型塑形上的精力。
  • 支持者将其描述为“把复杂性显式化”,而不是把它隐藏起来,从而产出更安全、更易调试的代码。
  • 对 Rust 中大型且深层的依赖树(精简的 stdlib、众多 crate、build.rs、与 GitHub 绑定的发布流程)以及相应的供应链风险,存在普遍担忧。
  • 捍卫者指出,C/C++ 往往通过 vendoring 或复制粘贴代码来“解决”这个问题,这只是把依赖关系隐藏起来,而不是消除它们。