- Published on
unsafe 与未定义行为(UB
unsafe 与未定义行为(UB)
什么是 UB
UB 是 Undefined Behavior(未定义行为)的缩写。
Rust 编译器假设 safe 代码不会触发 UB。一旦触发,编译器有权做出任何行为——崩溃、静默返回错误数据、甚至看似正常运行但在优化后突然出错,全部都是"合法"的。
常见的 UB 包括:解引用空指针、数据竞争、数组越界访问等。
unsafe 的意义
unsafe 的意义是告诉编译器:这段代码的正确性由程序员担保,编译器不再做安全假设。
当编译器无法验证一个操作是否安全,但程序员可以靠外部知识来保证时,用 unsafe 就是合理的。
实例:ThreadIndex::new
以本项目中 crates/cuda-device/src/thread.rs 的 ThreadIndex::new 为例:
pub struct ThreadIndex<'kernel, IndexSpace = Index1D> {
raw: usize,
// ...
}
impl<'kernel, IndexSpace> ThreadIndex<'kernel, IndexSpace> {
unsafe fn new(raw: usize, _scope: &'kernel KernelScope<'kernel>) -> Self {
ThreadIndex { raw, /* ... */ }
}
}
ThreadIndex 的设计保证每个线程的索引是唯一的,正是这个唯一性使得对 DisjointSlice 的并行写入无需同步也不会产生数据竞争。如果用户可以随意调用 new() 构造一个假的 ThreadIndex,就能伪造索引、破坏唯一性保证,从而产生数据竞争(UB)。
所以 new() 必须是 unsafe,把"我保证这个索引确实来自硬件线程 ID 计算"的责任推给调用者。模块内部的 index_1d、index_2d 等函数就是这些受信任的调用者——它们通过读取 CUDA 特殊寄存器来计算索引,可以安全地承担这个义务。
什么情况该用 unsafe
简单区分:
- 函数内部能通过运行时检查兜底 → 不需要
unsafe - 函数无条件信任调用方传入的值,而该值不合法会导致 UB → 应该用
unsafe
THE END