← [ BACK_TO_NOTES ]

Rust unsafe

unsafe 扩大信任边界而非关闭借用检查;能做什么、必须保证什么、如何封装安全抽象。

#concept #growing #dev #rust

[!info] related notes

Rust unsafe

这个概念为什么出现

安全 Rust 无法表达所有底层操作(原始指针、某些 FFI、手工布局)。
unsafe 让你进入需要额外人工证明的区域,同时仍保留大量编译检查。

[!abstract] 一句话理解 unsafe 允许五类超能力(裸指针解引用、unsafe 函数、可变静态、union 字段、实现 unsafe trait);不变量由程序员保证,应用安全封装对外。

最小可运行示例

场景:区分安全切片 API 与需要调用方证明的裸指针 API

空指针与长度检查不能证明地址存活、已初始化或不存在数据竞争。安全入口直接接收切片;确需裸指针时,用 unsafe fn 暴露证明义务,不能仅写一条“调用方保证”就声称函数安全。

// 裸指针入口必须将无法运行时验证的契约交给调用方。
/// # Safety
/// 若 data 非空且 len > 0,data 必须指向一个存活、已初始化的 u8,
/// 并且读取期间没有并发写入。此函数仅读取首字节,不验证整段 len。
unsafe fn first_byte_raw(data: *const u8, len: usize) -> Option<u8> {
    if data.is_null() || len == 0 {
        return None;
    }
    // SAFETY: 调用方保证首字节有效且可读,当前分支已排除空指针。
    Some(unsafe { *data })
}

fn first_byte(data: &[u8]) -> Option<u8> {
    data.first().copied()
}

fn main() {
    let buf = [9u8, 8, 7];
    println!("{:?}", first_byte(&buf));
    println!("{:?}", first_byte(&[]));
    // SAFETY: buf 在调用期间存活、已初始化且未被修改。
    assert_eq!(unsafe { first_byte_raw(buf.as_ptr(), buf.len()) }, Some(9));
}

建议运行:cargo run

期望:

Some(9)
None

结合场景再看三个关注点

  1. SAFETY 注释写清前提
  2. 安全入口须对所有合法安全调用成立;无法检查的指针契约不能藏在 safe 函数内
  3. 最小化 unsafe 行数

核心概念与准确模型

unsafe 超能力(教学列表):

  1. 解引用裸指针
  2. 调用 unsafe fn
  3. 访问/修改可变静态
  4. 实现 unsafe trait
  5. 读 union 字段

未定义行为(UB)例子:悬垂、越界、数据竞争、无效枚举判别式…

安全抽象必须在所有合法安全调用下保持不变量;仅缩小 unsafe 块不能证明封装 sound。Rust 2024 中 unsafe fn 内的具体操作仍应显式放入 unsafe 块,声明契约与履行契约是两回事。

设计动机

  • 系统编程需要底层
  • 把危险集中审查
  • 不逼所有代码进入 unsafe

边界与误区

  • “有 unsafe 就随便” → UB
  • 大范围 unsafe 块
  • 无测试/无 Miri

[!warning] 常见误区:用 unsafe 绕过借用检查偷懒 正确动机应是表达安全 Rust 无法表达且已证明的不变量。

工程实践

  1. 最小权限 unsafe
  2. 文档 + SAFETY 注释
  3. 用 Miri/测试发现已覆盖路径中的问题;通过不等于对所有输入的安全证明
  4. 代码评审强制

本节总结

  • unsafe = 信任边界
  • 封装安全 API
  • 与 FFI/性能相关

自测题

  1. unsafe 会关闭借用检查吗?
  2. 为什么要写 SAFETY 注释?
参考答案
  1. 不会整体关闭;只允许额外操作。
  2. 记录证明义务,供审计与未来修改。

延伸阅读与资料来源

资料类型支撑内容
The Book — Unsafe Rust官方书unsafe
Rustonomicon官方不变量与 UB
Miri工具检测 UB
创建于 2026/7/15 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本