编程系统程序员 / Rust高级开发者

什么是Unsafe Rust,它的用途是什么,它的规则是什么,如何正确使用unsafe块以最小化风险?

用 Hintsage AI 助手通过面试

答复

Unsafe Rust是Rust安全子集的扩展,允许使用编译器无法验证的所有权、生命周期和别名的操作。主要应用领域包括:与低级库的交互、FFI、手动内存控制、实现不符合安全Rust模型的抽象。

Unsafe的关键特性:

  • 使用时需要明确声明块:unsafe { ... }或函数:unsafe fn some_func()
  • 在unsafe块中允许不安全操作:解引用原始指针、调用不安全函数和方法、访问union、静态可变变量、实现非结构化内存的方法
  • 使用unsafe并不会使块内的所有代码对整个语言来说都是危险的——只需手动保证正确性

示例:

let x: i32 = 10; let ptr: *const i32 = &x as *const i32; unsafe { println!("Value: {}", *ptr); // 解引用原始指针 }

反问

在unsafe块内的代码是否完全不安全且不受编译器检查,或者编译器是否仍然应用借用检查器和其他检查?

答复: 不,在unsafe块内,编译器仍然检查Rust的许多规则(例如,类型、所有权规则、语法),但允许仅执行那些否则不允许的操作。不能完全禁用借用检查器!

示例:

let mut x = 0; let r1 = &mut x as *mut i32; // 被禁止: let r2 = &mut x as *mut i32; // 即使在unsafe中,若违反可变性也会出现错误

由于对主题细微差别不熟悉而导致的实际错误示例


故事

在异步文件库中使用了原始指针来控制缓冲区,但忘记正确跟踪缓冲区的生命周期。结果,在关闭文件时,指针变成“悬挂的”,访问导致未定义行为(unsafe部分未能避免use-after-free)。


故事

在自己实现的类似Vec的结构中,程序员通过unsafe手动扩展缓冲区。偏移错误导致元素复制不正确和数据损坏,因为未考虑类型的对齐和布局。


故事

在线程描述符中使用了静态可变指针(static mut),没有适当的同步。因此,在多线程模式下意外出现数据竞争,导致应用程序偶发崩溃,仅通过模糊测试检测到。