Rust 非安全Rust能做什么
非安全Rust比安全Rust可以多做的事情只有以下几个:
- 解引用裸指针
- 调用非安全函数(包括C语言函数,编译器内联函数,还有直接内存分配等)
- 实现非安全trait
- 访问或修改可变静态变量
就这些。这些操作被归为非安全的,是因为使用得不正确就会导致可怕的未定义行为。一旦触发了未定义行为,编译器就可以放飞自我,肆意破坏你的程序。切记,一定不能给未定义行为任何的机会。
与C不同,Rust充分限制了可能出现的未定义行为的种类。语言核心只需要防止这几种行为:
- 解引用null指针,悬垂指针,或者未赋值的指针
- 读取未初始化的内存
- 破坏指针混淆规则
- 创建非法的基本类型:
- 悬垂引用与null引用
- 空的
fn
指针 - 0和1以外的
bool
类型值 - 未定义的枚举类型的项
- 在[0x0,0xD&FF]和[0xE000, 0x10FFFF]以外的
char
类型值 - 非utf-8编码的
str
- 不谨慎地调用其他语言
- 数据竞争
只有这些。Rust语言自身可以导致未定义行为的操作就只有这些。当然,非安全函数和trait可以声明自己专有的安全规范,要求开发者必须遵守以避免未定义行为。比如,allocator API声明回收一段未分配的内存是未定义行为。
但是,违背这些专有的规范通常也只是间接地触发上面列出的行为。另外,编译器内联函数也可能引入一些规则,一般是针对代码优化的假设条件。比如,Vec和Box使用的内联函数要求传入的指针永远不能为null。
Rust对于一些模糊的操作则通常比较宽容。Rust会认为下列操作是安全的:
- 死锁
- 竞争条件
- 内存泄漏
- 调用析构函数失败
- 整型值溢出
- 终止程序
- 删除产品数据库
当然,有以上行为的程序极有可能就是错误的。Rust提供了一系列的工具减少这种事情的发生,但是完全地杜绝它们其实是不现实的。
Rust通常要求我们明确限制非安全Rust代码的作用域。可是,现实情况其实要更复杂一些。举个例子,看一下下面的代码:fn index(idx: usize, arr: &[u8]) -> Option ...