不被认为是 unsafe 的行为

Rust 编译器不认为以下行为是不安全的,尽管程序员可能(应该)认为它们是不希望的、意外的或错误的。

死锁
内存和其他资源的泄漏
在未调用析构函数的情况下退出
通过指针泄漏暴露随机化的基地址
整数溢出

如果程序包含算术溢出,则程序员犯了一个错误。在以下讨论中,我们区分算术溢出和环绕算术。前者是错误的,而后者是故意的。

当程序员启用 debug_assert! 断言(例如,通过启用非优化构建)时,实现必须插入动态检查,在溢出时 panic。其他类型的构建可能会导致 panic 或在溢出时静默地环绕值,具体由实现决定。

在隐式环绕溢出的情况下,实现必须通过使用二进制补码溢出约定来提供定义良好的(即使仍然被认为是错误的)结果。

整数类型提供了固有的方法,允许程序员显式地执行环绕算术。例如,i32::wrapping_add 提供二进制补码、环绕加法。

标准库还提供了一个 Wrapping<T> newtype,它确保 T 的所有标准算术运算都具有环绕语义。

有关错误条件、基本原理以及有关整数溢出的更多详细信息,请参阅 RFC 560

逻辑错误

安全的代码可能会施加额外的逻辑约束,这些约束既不能在编译时也不能在运行时检查。如果程序违反了这样的约束,则行为可能是未指定的,但不会导致未定义行为。这可能包括 panic、错误的结果、中止和非终止。行为也可能在运行、构建或构建类型之间有所不同。

例如,同时实现 HashEq 需要将认为相等的值具有相等的哈希值。另一个例子是诸如 BinaryHeapBTreeMapBTreeSetHashMapHashSet 之类的数据结构,它们描述了在数据结构中修改键的约束。违反这些约束不被认为是不安全的,但程序被认为是错误的,并且其行为是不可预测的。