Rust unsafe
unsafe 扩大信任边界而非关闭借用检查;能做什么、必须保证什么、如何封装安全抽象。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust unsafe
这个概念为什么出现
安全 Rust 无法表达所有底层操作(原始指针、某些 FFI、手工布局)。
unsafe 让你进入需要额外人工证明的区域,同时仍保留大量编译检查。
[!abstract] 一句话理解
unsafe允许五类超能力(裸指针解引用、unsafe 函数、可变静态、union 字段、实现 unsafe trait);不变量由程序员保证,应用安全封装对外。
最小可运行示例
场景:安全封装——从裸指针读取需要信任的长度
演示“unsafe 块尽量小 + 安全函数边界检查”。
// 业务意图:在已校验长度的前提下读取首字节。
// 教学点:安全 API 做检查;unsafe 仅解引用。
fn first_byte(data: *const u8, len: usize) -> Option<u8> {
if data.is_null() || len == 0 {
return None;
}
// SAFETY: 调用方保证 data 指向至少 len 字节可读;我们已排除空与零长。
// 此处示例假定调用方契约成立(教学用)。
let b = unsafe { *data };
Some(b)
}
fn main() {
let buf = [9u8, 8, 7];
println!("{:?}", first_byte(buf.as_ptr(), buf.len()));
println!("{:?}", first_byte(std::ptr::null(), 0));
}
建议运行:cargo run
期望:
Some(9)
None
结合场景再看三个关注点
- SAFETY 注释写清前提
- 检查放在 safe 边界
- 最小化 unsafe 行数
核心概念与准确模型
unsafe 超能力(教学列表):
- 解引用裸指针
- 调用
unsafe fn - 访问/修改可变静态
- 实现
unsafe trait - 读 union 字段
未定义行为(UB)例子:悬垂、越界、数据竞争、无效枚举判别式…
安全抽象:对外 100% safe API,对内局部 unsafe。
设计动机
- 系统编程需要底层
- 把危险集中审查
- 不逼所有代码进入 unsafe
边界与误区
- “有 unsafe 就随便” → UB
- 大范围 unsafe 块
- 无测试/无 Miri
[!warning] 常见误区:用 unsafe 绕过借用检查偷懒 正确动机应是表达安全 Rust 无法表达且已证明的不变量。
工程实践
- 最小权限 unsafe
- 文档 + SAFETY 注释
- 用 Miri/测试加固
- 代码评审强制
本节总结
- unsafe = 信任边界
- 封装安全 API
- 与 FFI/性能相关
自测题
- unsafe 会关闭借用检查吗?
- 为什么要写 SAFETY 注释?
参考答案
- 不会整体关闭;只允许额外操作。
- 记录证明义务,供审计与未来修改。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Unsafe Rust | 官方书 | unsafe |
| Rustonomicon | 官方 | 不变量与 UB |
| Miri | 工具 | 检测 UB |