gpt4 book ai didi

rust - 从语义的角度来看,Rust 中发生 `&mut` noalias 的未定义行为是什么时候?

转载 作者:行者123 更新时间:2023-12-03 11:25:02 26 4
gpt4 key购买 nike

正如 Rust 引用文档所说

Breaking the pointer aliasing rules. &mut T and &T follow LLVM’s scoped noalias model, except if the &T contains an UnsafeCell.



真是模棱两可。
我想知道 &mut 未定义行为的确切时刻是什么? noalias 发生在 Rust 中。

是下面的还是别的?

  1. When defining two &mut that point to the same address?
  2. When two &mut that point to the same address exposed to rust?
  3. When perfrom any operation on a &mut that point to the same address of any other &mut?


例如, this code显然是 UB:

unsafe {
let mut x = 123usize;
let a = (&mut x as *mut usize).as_mut().unwrap(); // created, but not accessed
let b = (&mut x as *mut usize).as_mut().unwrap(); // created, accessed
*b = 666;
drop(a);
}

但是如果我修改像 this 这样的代码怎么办? :

struct S<'a> {
ref_x: &'a mut usize
}

fn main() {
let mut x = 123;
let s = S { ref_x: &mut x }; // like the `T` in `ManuallyDrop<T>`
let taken = unsafe { std::ptr::read(&s as *const S) }; // like `ManuallyDrop<T>::take`
// at thist ime, we have two `&mut x`
*(taken.ref_x) = 666;
drop(s);
// UB or not?
}

第二个版本也是UB吗?
第二个版本与 std::mem::ManuallyDrop 的实现完全相同.如果第二个版本是UB,是不是 std::mem::ManuallyDrop<T>的安全bug ?

最佳答案

别名限制不是什么

实际上,存在多个 &mut T 是很常见的。别名相同的项目。

最简单的例子是:

fn main() {
let mut i = 32;
let j = &mut i;
let k = &mut *j;

*k = 3;

println!("{}", i);
}

但请注意,由于借用规则,您无法同时访问其他别名。

如果你看看 ManuallyDrop::take 的实现:

pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
ptr::read(&slot.value)
}


您会注意到没有同时可访问的 &mut T : 调用函数重新借用 ManuallyDrop制作 slot唯一可访问的可变引用。

为什么 Rust 中的别名如此不明确

It's really ambiguous. I want to know that what's the exactly moment an undefined behavior of &mut noalias occurred in Rust.



运气不好,因为如 Nomicon 中所述:

Unfortunately, Rust hasn't actually defined its aliasing model.



原因是语言团队希望确保他们达到的定义既安全(显然如此)、实用,又不会关闭可能的改进之门。这是一项艰巨的任务。

Rust Unsafe Code Guidelines Working Group仍在努力建立确切的边界,特别是 Ralf Jung 正在研究一种名为 Stacked Borrows 的别名操作模型。 .

注意:Stacked Borrows 模型是在 MIRI 中实现的,因此您只需在 MIRI 中执行您的代码,就可以根据 Stacked Borrows 模型验证您的代码。当然,Stacked Borrows 仍然是实验性的,所以这并不能保证任何事情。

什么谨慎建议

我个人赞成谨慎。由于未指定确切的模型,因此规则不断变化,因此我建议尽可能采取更严格的解释。

因此,我解释了 &mut T 的无锯齿规则作为:

At any point in the code, there shall not be two accessible references in scope which alias the same memory if one of them is &mut T.



也就是说,我认为形成一个 &mut T到实例 T另一个 &T&mut T在没有使别名无效的情况下(通过借用)在范围内是格式错误的。

这很可能过于谨慎,但至少如果混叠模型最终比计划更保守,我的代码仍然有效。

关于rust - 从语义的角度来看,Rust 中发生 `&mut` noalias 的未定义行为是什么时候?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62066069/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com