---
title: unsafe 块与 Soundness 契约
url: https://doc.liz6.com/rust/07-unsafe-rust/02-unsafe-blocks-and-the-soundness-contract
locale: zh
area: rust
tags:
- rust
- Unsafe Rust
date: 2026-06-30
modified: 2026-06-30
description: unsafe 关键字不"禁用"安全检查,而是把本由编译器保证的安全契约转交给程序员保证——你可以解引用裸指针、调用 unsafe 函数、访问可变静态变量,但你必须确保无论调用方怎么做,都不会触发 UB(未定义行为)。写 unsafe 代码的真正难点不是"能写出来",而是为它封装一个安全的抽象外壳。
---

# unsafe 块与 Soundness 契约

> `unsafe` 关键字不"禁用"安全检查,而是把本由编译器保证的安全契约转交给程序员保证——你可以解引用裸指针、调用 unsafe 函数、访问可变静态变量,但你必须确保无论调用方怎么做,都不会触发 UB(未定义行为)。写 unsafe 代码的真正难点不是"能写出来",而是为它封装一个安全的抽象外壳。

## unsafe 不是"禁用所有安全检查"

`unsafe {}` 块只开启 5 项能力，其余的 Rust 安全检查依然生效：

1. 解引用裸指针 (`*const T`, `*mut T`)
2. 调用 `unsafe fn`
3. 访问或修改 `static mut` 变量
4. 实现 `unsafe trait` (如 `Send`, `Sync`, `GlobalAlloc`)
5. 访问 `union` 的字段

**Borrow checker 在 unsafe 块内仍然有效**——你不能创建两个 `&mut T` 指向同一数据，这是 UB，编译器在 unsafe 中依然会拒绝。

理解 unsafe 的关键：它不是"我来承担所有安全责任"，而是"我承担编译器无法自动验证的那部分责任"。

## Soundness: 安全的边界

`unsafe fn` 的签名定义了**契约**。调用者必须满足前置条件，否则可能产生 UB。标准库中到处是这样的模式：

```rust
// 对外安全, 内部 unsafe — 调用者只需要传对参数, 不需要写 unsafe
pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
    assert!(mid <= self.len());      // 运行时检查 — 这是安全边界!
    let ptr = self.as_mut_ptr();
    unsafe { (from_raw_parts_mut(ptr, mid),
              from_raw_parts_mut(ptr.add(mid), self.len() - mid)) }
}
```

如果 assert 通过，下面的 unsafe 操作就是 sound 的——`mid <= len` 保证了两段 slice 不重叠。如果 assert 失败，直接 panic——不会进入 unsafe 区域。这是标准库最常用的模式：**safe code 验证条件，unsafe code 在条件成立的前提下执行**。

关键：unsafe 代码的 soundness 不仅依赖于 unsafe 块内的逻辑，还依赖于**外部 safe code 维护的不变量**。如果你写的 unsafe 代码假设了某个数据结构的不变量（如 `len <= cap`），那么外部所有修改该数据结构的 safe 代码都必须维护这个不变量。

## UB (Undefined Behavior): 必须避免的清单

- 解引用空指针、悬垂指针、未对齐指针
- 违反借用规则（即使在 unsafe 中）
- 数据竞争
- 用错误的 ABI 调用函数
- 产生不合法的值：`bool` 非 0 非 1、引用为空、`char` 是 surrogate
- unwind 穿过 FFI 边界（`extern "C"` 函数中 panic）

## Miri: 自动化 UB 检测

Miri 在 MIR 级别解释执行 Rust，追踪 provenance 和 borrow 状态：

```bash
cargo +nightly miri test
```

可以检测：use-after-free、out-of-bounds access、data races、alignment violations。任何有 `unsafe` 的 crate 都应该跑 Miri——它不能证明 soundness，但能发现明显的 UB。

## 参考

- **Rustonomicon**: "What Unsafe Can Do", Soundness requirements
- **Rust Reference**: Behavior considered undefined
- **Miri**: github.com/rust-lang/miri

*Keywords: unsafe, soundness, UB, Miri, safety contract, invariant, raw pointer*
