内容提要
Robert Seacord在RustConf 2026指出,Rust虽以内存安全著称,但Unsafe Rust的语言语义仍多未定,缺少完整形式化内存模型,UB、指针provenance与别名规则尚无定论,编译器行为与Miri等来源也不完全一致。Rust需定义、验证并审计unsafe,才能进入汽车、内核等安全关键领域。
延伸解读
Unsafe Rust 的语义未决状态
Robert Seacord 指出,Unsafe Rust 的语言语义仍有相当部分处于未决状态,缺少完整的形式化内存模型。这意味着指针 provenance、别名规则等底层行为尚未最终确定,不同来源如 Rust Reference、Miri 和编译器行为可能不一致。对于依赖 Unsafe 的代码,当前能运行并不代表未来版本仍被允许,开发者需关注语言规范的演进。
未定义行为对安全关键系统的影响
在 Unsafe Rust 中,未定义行为(UB)是核心风险。一旦发生 UB,编译器可基于“UB 不会发生”进行优化,导致测试通过的程序在优化后行为异常。Seacord 强调,包含 UB 的程序其测试结果不能证明正确性。对于汽车、内核等安全关键领域,消除 UB 是建立安全保证的前提,仅靠测试无法满足要求。
指针 provenance 与优化之间的权衡
指针不仅包含地址,还包含 provenance,相同地址可能因来源不同而具有不同访问权限。语言设计者引入 provenance 是为了支持编译器的别名分析,从而进行更激进的优化。但这与保留传统底层指针技巧存在张力,Seacord 形容为“鱼与熊掌难以兼得”。开发者需理解这一权衡,避免依赖未确定的指针行为。
Unsafe Rust 的工程实践建议
Seacord 建议将 Unsafe 的使用限制在明确知道安全要求且能验证的语言子集中。具体包括:小范围使用、明确记录安全不变量、将 Unsafe 封装在 Safe API 后、使用 Miri 等工具辅助检查、避免依赖未确定的语言行为,并在编译器升级后重新评估关键 Unsafe 代码。这些做法有助于将危险压缩在可审查的边界内。
Q&A
Rust 不是号称内存安全吗?为什么还需要 Unsafe Rust?
Rust 的内存安全建立在 Safe Rust 基础上,但系统编程需要裸指针、FFI、unsafe trait、底层汇编等能力,这些必须通过 Unsafe Rust 实现。例如 Linux 内核中约 10% 的 Rust 代码标记为 unsafe,底层抽象中甚至可达 30%~50%。Unsafe Rust 不是 Rust 的失败,而是它进入系统编程世界的重要原因。
Unsafe Rust 目前最大的问题是什么?
最大的问题是 Unsafe Rust 的语言语义仍有相当一部分处于未决状态。Rust 缺少完整的形式化内存模型,Unsafe 操作必须满足哪些不变量尚未最终确定。这意味着今天能运行的行为,未来 Rust 版本不一定继续允许,编译器升级后可能需要重新评估关键 Unsafe 代码。
什么是 Undefined Behavior?为什么测试通过也不能证明 Unsafe 代码正确?
Undefined Behavior 指一个操作没有合法的下一状态。一旦发生 UB,编译器可以假设它不会发生并据此优化,这些假设可能影响整个程序。因此包含 UB 的程序,其测试结果不能用来证明程序行为,未经优化时运行正常、开启优化后结果完全不同的情况在 C/C++ 中很常见。
Pointer Provenance 是什么?为什么相同地址的指针可能有不同权限?
Pointer Provenance 指指针的来源或出处。一个指针不仅包含地址,还包含 provenance。一次内存访问是否产生 UB,同时取决于 pointer 的 address 和 provenance;即使两个指针指向相同地址,也可能因 provenance 不同而产生不同结果。语言设计者引入 provenance 是为了让编译器进行更强的别名分析和优化。
遇到底层 Unsafe Rust 问题时,应该参考哪些来源?它们可靠吗?
可以参考 Rust Reference、编译器实际行为、Miri、Unsafe Code Guidelines、专家讨论和社区意见。但这些来源并不总是完全一致,例如 Rust Reference 的表述与 Miri 的实际判断可能存在差异。Miri 是有价值的工具,但其行为不自动等于语言规范;某个编译器版本允许的行为也不代表跨平台、跨版本的语言保证。
编写 Unsafe Rust 代码时应该遵循哪些实践建议?
应只使用明确知道安全要求且能验证的语言子集,把 unsafe 理解为需要程序员自己证明安全不变量。具体建议包括:小范围使用 unsafe、明确记录 Safety Invariant、将 Unsafe 封装在 Safe API 后面、使用 Miri 等工具辅助检查、避免依赖尚未确定的语言行为,并在编译器升级后重新评估关键 Unsafe 代码。
Rust 要进入汽车、内核等安全关键领域,还需要解决什么?
Rust 需要定义、验证并审计 unsafe。安全关键系统最终要回答“这段代码为什么安全”,这要求先明确 Rust 到底定义了什么是安全、什么是 UB,以及编译器被允许做什么。Rust 的下一阶段不是减少 unsafe,而是定义 unsafe,让 unsafe 变得可定义、可验证、可审计。