为什么实例化 core::time::Nanoseconds 不安全?

问题描述 投票:0回答:1

我正在漫步

core::time
,并对
Nanoseconds
的实施感到惊讶。 为什么实例化它需要一个
unsafe
块? 我理解有关
Nanoseconds
范围限制的评论(必须是 <
NANOS_PER_SEC
),但是
unsafe
在这种情况下有何帮助?

如果我将代码复制到自定义包中(编译器内部结构除外,它们不稳定):

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
struct Nanoseconds(u32);

impl Default for Nanoseconds {
    #[inline]
    fn default() -> Self {
        // SAFETY: 0 is within the valid range
        unsafe { Nanoseconds(0) }
    }
}

fn main() {
    let nanos = Nanoseconds(0);
    println!("Nanos: {}", nanos.0);
}

我从 rustc 收到以下警告:

warning: unnecessary `unsafe` block
 --> src/main.rs:9:9
  |
9 |         unsafe { Nanoseconds(0) }
  |         ^^^^^^ unnecessary `unsafe` block
  |
  = note: `#[warn(unused_unsafe)]` on by default

warning: `test_nanos` (bin "test_nanos") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/test_nanos`
Nanos: 0

由于

Nanoseconds
只是一个元组结构,因此应该可以在没有周围
unsafe
块的情况下实例化它,对吗?

rust abi
1个回答
4
投票

因为

#[rustc_layout_scalar_valid_range_*(…)]
属性告诉编译器它可以基于存储在 Nanoseconds 中的值永远不会超出它们指定的范围的假设来优化
1
代码。因此,创建一个值超出范围的 Nanoseconds
未定义行为 (UB)

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
#[rustc_layout_scalar_valid_range_end(999_999_999)]
struct Nanoseconds(u32);

关于 UB 的参考文献中的相关部分

  • 即使在私人领域和当地人中也会产生无效值。每当将值分配给某个位置或从某个位置读取值、传递给函数/基元操作或从函数/基元操作返回值时,就会“生成”值。以下值无效(在其各自的类型中):
    • […]

    • 具有无效值自定义定义的类型的无效值。在标准库中,这会影响

      NonNull<T>
      NonZero*

      注意:

      rustc
      通过不稳定的
      rustc_layout_scalar_valid_range_*
      属性实现了这一点。

允许编译器假设

Nanoseconds
中的值始终在
0..=999_999_999
内并进行相应优化。

这类似于占据整个字节的

bool
,但仅允许值
0
1
,而
2..=255
是无效值。


1) 例如,它可以省略像

nanos.0 <= 999_999_999
这样的边界检查,或者它可以使用
1_000_000_000
及以上作为
enum

中的 nieche
© www.soinside.com 2019 - 2024. All rights reserved.