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 ...