&mut T
and &mut T
导致编译错误;这太棒了,两次可变借用在客观上是错误的。
Is *mut T
and*mut T
未定义的行为还是这是完全有效的事情?也就是说,可变指针别名有效吗?
更糟糕的是&mut T
and *mut T
实际上编译并按预期工作,我可以通过引用、指针修改值,然后再次引用......但我看到有人说这是未定义的行为。是的,“有人这么说”是我所掌握的唯一信息。
这是我测试的:
fn main() {
let mut value: u8 = 42;
let r: &mut u8 = &mut value;
let p: *mut u8 = r as *mut _;
*r += 1;
unsafe { *p += 1; }
*r -= 1;
unsafe { *p -= 1; }
println!("{}", value);
}
当然,问题的要点是:
Note— 感谢 trentcl指出这个例子实际上在创建时会产生一个副本p2 https://stackoverflow.com/questions/57364654/is-mut-t-aliasing-in-rust-ub#comment101216866_57364654。这可以通过替换来确认u8
与非Copy
类型。然后编译器抱怨移动。遗憾的是,这并没有让我更接近答案,只是提醒我,我可能会得到意想不到的行为,而不会是未定义的行为,这仅仅是因为 Rust 的移动语义。
fn main() {
let mut value: u8 = 42;
let p1: *mut u8 = &mut value as *mut _;
// this part was edited, left in so it's easy to spot
// it's not important how I got this value, what's important is that it points to same variable and allows mutating it
// I did it this way, hoping that trying to access real value then grab new pointer again, would break something, if it was UB to do this
//let p2: *mut u8 = &mut unsafe { *p1 } as *mut _;
let p2: *mut u8 = p1;
unsafe {
*p1 += 1;
*p2 += 1;
*p1 -= 1;
*p2 -= 1;
}
println!("{}", value);
}
两者产量:
42
这是否意味着指向同一位置并在不同时间取消引用的两个可变指针不是未定义的行为?
我认为一开始就在编译器上测试这个不是一个好主意,因为未定义的行为可能会发生任何事情,甚至打印42
好像什么事都没有一样。无论如何我提到它,因为这是我尝试过的事情之一,希望得到客观的答案。
我不知道如何编写一个测试,该测试可能会强制出现不稳定的行为,这会明显表明这是行不通的,因为它没有按预期使用,如果有可能这样做的话。
我知道这很可能是未定义的行为,并且无论如何都会在多线程环境中中断。不过,我希望得到比这更详细的答案,特别是如果可变指针别名不是未定义的行为。 (这实际上非常棒,因为虽然我使用 Rust 的原因和其他人一样——至少可以说是内存安全……我希望仍然保留一把可以指向任何地方的霰弹枪,而不会被锁在我的脚上。我可以使用别名“可变指针”,而不会在 C 中大吃一惊。)
这是一个关于我是否can,而不是关于我是否should。我想深入研究不安全的 Rust,只是为了了解它,但感觉没有足够的信息,不像 C 等“可怕”的语言,关于什么是未定义行为,什么不是。