不被视为 unsafe 的行为

Rust 编译器不认为以下行为是 unsafe 的,尽管程序员可能(应该)认为它们是不 desirable、unexpected 或 erroneous 的。

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

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

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

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

整数类型提供固有方法,允许程序员明确执行回绕算术。例如,i32::wrapping_add 提供补码回绕加法。

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

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

逻辑错误

安全代码可能强制实施无法在编译时或运行时检查的额外逻辑约束。如果程序违反了此类约束,其行为可能是未指定的,但不会导致未定义行为。这可能包括 panics、不正确的结果、终止以及非终止。行为也可能在不同运行、构建或构建类型之间有所差异。

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