想象一下,您正试图编写一个围绕一些可变静态变量的安全包装器:

#![feature(strict_provenance)]
#![deny(fuzzy_provenance_casts)]
#![deny(lossy_provenance_casts)]

struct Wrapper<T>(*mut T);
struct Guard<T>(*mut T);

impl<T> Wrapper<T> {
    fn guard(&self) -> Guard<T> {
        Guard(self.0)
    }
}

// imagine there's synchronization going on that makes this all safe
unsafe impl<T: Send + Sync> Sync for Wrapper<T> {}
impl<T> std::ops::Deref for Guard<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.0 }
    }
}
impl<T> std::ops::DerefMut for Guard<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.0 }
    }
}

static mut GLOBAL_SINGLETON: isize = 0; // Imagine this couldn't be trivially replaced by an atomic type
static WRAPPER: Wrapper<isize> = Wrapper(unsafe { &GLOBAL_SINGLETON as *const _ as *mut _ });
//                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                                             Is this sound in this sepcific instance?

// Actually dereference the raw pointer to provoke UB
fn main() {
    assert_eq!(0, *WRAPPER.guard());
    *WRAPPER.guard() += 1;
    assert_eq!(1, *WRAPPER.guard());
}

现在,通常情况下,强制转换&T as *const T as *mut T并写入结果原始指针是不合理的,但严格来源和MIRI都不会抱怨上面的代码.这是由于堆叠借款和/或MILI的限制而导致的假阴性吗?还是会有static mut件商品在全局被贴上SharedRW件的标签,并在这里获得免费通行证?Ctrl-F代表Stacked Borrows paper中的"静态"没有显示任何相关信息.

我也考虑过这样的事情,我更喜欢这样,因为它迫使TWrapper活得更长.

struct Wrapper<'a, T>(&'a std::cell::UnsafeCell<T>);
impl<'a, T> Wrapper<'a, T> {
    const fn new(t: &'a T) -> Self {
        Self(unsafe { std::mem::transmute(t) }
    }
}
// ...

static mut GLOBAL_SINGLETON: isize = 0;
static WRAPPER: Wrapper<'_, isize> = Wrapper::new(&GLOBAL_SINGLETON);
// ...

但这显然是不合理的(Miri会告诉你),因为它需要&GLOBAL_SINGLETON个才能活着,而&UnsafeCell { GLOBAL_SINGLETON }个人才能活着.

推荐答案

现有的两个答案都表明这是UB,所以我添加了一个我自己的答案,以反映Ralf Jung更细微的输入.如果有人知道的话,我想一定是他:

这是因为我们在编译时没有别名模型,所以没有人会记住这个指针源自共享引用.我们还没有决定别名规则是否适用于编译时和运行时之间的边界.我认为它们在这里并不是特别有用,因为一切都是全球性的……但这是一个UCG的问题.1

它深陷未确定/未指明的领域.所以请不要这么做.:)2

So this isn't definitely UB but it also isn't definitely not UB 和 should be avoided pending a decision.

拉尔夫还在UCG repo中创建了a new issue个来解决这个问题,请参见future 的发展.

1 : https://github.com/rust-lang/miri/issues/2937#issuecomment-1600365067

2 : https://github.com/rust-lang/miri/issues/2937#issuecomment-1602458297

Rust相关问答推荐

如何处理对打包字段的引用是未对齐错误?

如何在Rust中为具有多个数据持有者的enum变体编写文档 comments ?

无需通过ASIO输入音频,并使用cpal进行反馈示例

如何从polars DataFrame中获取一个列作为Option String?<>

是否可以为`T:Copy`执行`T. clone`的测试

"value is never read警告似乎不正确.我应该忽略它吗?

在我的Cargo 中,当我在建筑物中使用时,找不到我可以在产品包中使用的 crate .r我如何解决这个问题?

如何在Rust中将选项<;选项<;字符串>;转换为选项<;选项&;str>;?

我如何使用AWS SDK for Rust获取我承担的角色的凭据?

对于rustc编译的RISC-V32IM二进制文件,llvm objdump没有输出

是否可以使用Serde/Rust全局处理无效的JSON值?

什么是`&;[][..]`铁 rust 里的刻薄?

通过异常从同步代码中产生yield 是如何工作的?

RUST 中的读写器锁定模式

我们可以在 Rust 切片中使用步骤吗?

sha256 摘要仅适用于 &*

&self 参数在 trait 的功能中是必需的吗?

n 个范围的笛卡尔积

Rust 中的let是做什么的?

在 Rust 中返回对枚举变体的引用是个好主意吗?