Rust 从语义角度看,什么';现在是`&;在锈病中发生的突变?
正如参考文献所说 打破指针别名规则&mut T和&T遵循LLVM的作用域noalias模型,除非&T包含一个未完成单元 这真是模棱两可。Rust 从语义角度看,什么';现在是`&;在锈病中发生的突变?,rust,llvm,undefined-behavior,unsafe,Rust,Llvm,Undefined Behavior,Unsafe,正如参考文献所说 打破指针别名规则&mut T和&T遵循LLVM的作用域noalias模型,除非&T包含一个未完成单元 这真是模棱两可。 我想知道noalias在Rust中发生未定义行为的确切时刻是什么时候 它是下面的任何一个,还是别的什么 定义指向同一地址的两个&mut时 当两个&mut指向同一地址时,会生锈吗 当在指向任何其他&mut相同地址的&mut上执行任何操作时 例如,观察到: 不安全{ 让mut x=123使用; 设a=(&mut x as*mut usize).as_mut().u
我想知道noalias在Rust中发生未定义行为的确切时刻是什么时候 它是下面的任何一个,还是别的什么
&mut
时李>
&mut
指向同一地址时,会生锈吗&mut
相同地址的&mut
上执行任何操作时不安全{
让mut x=123使用;
设a=(&mut x as*mut usize).as_mut().unwrap();//已创建,但未访问
设b=(&mut x as*mut usize).as_mut().unwrap();//创建、访问
*b=666;
下降(a);
}
但是如果我修改代码,比如:
struct不受别名限制
实际上,多个现有的&mut T 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(插槽:&mut-ManuallyDrop)->T{
ptr::读取(&slot.value)
}
您将注意到,没有同时可访问的&mut T
:调用函数会重新借用ManuallyDrop
使slot
成为唯一可访问的可变参考
为什么Rust中的别名定义如此模糊
这真是模棱两可。我想知道noalias在Rust中发生未定义行为的确切时刻是什么时候
运气不好,因为按照合同规定:
不幸的是,Rust实际上还没有定义它的别名模型
原因是语言团队希望确保他们达成的定义既安全(显然如此)、实用,又不会关闭可能的改进之门。这是一项艰巨的任务
该公司仍在致力于建立精确的边界,特别是拉尔夫·荣格(Ralf Jung)正在致力于一个名为
注意:堆叠借用模型是在MIRI中实现的,因此您只需在MIRI中执行代码,就可以根据堆叠借用模型验证代码。当然,堆叠借款仍然是实验性的,所以这不能保证任何事情
谨慎的建议是什么
我个人赞成谨慎。鉴于确切的模型尚未确定,规则不断变化,因此我建议尽可能采用更严格的解释
因此,我将&mut T T
的无混叠规则解释为:
在代码中的任何一点上,如果其中一个是&mut T
,则范围内不得有两个可访问的引用别名相同的内存
这是一个实例:<代码>和MUT T >代码>一个实例<代码> t>代码>,其中另一个<代码> &t>代码>或<代码>和MUT T <代码>在范围内,而不使别名无效(通过借用)。
这很可能过于谨慎,但至少如果别名模型最终比计划的更保守,我的代码仍然有效。“您有责任确保此ManuallyDrop不再使用”-这是否引用了您为回答问题而链接的文档?@Cerberus否。在第一个示例中,我们没有取消引用a
,但它是UB。在第二个例子中,这是与ManuallyDrop
相同的实现,我们也做了两个别名&mut
引用,但只区分了一个,就像确保这个ManuallyDrop不再被使用一样,是不是也应该是UB?很抱歉,我只是不明白(2)和(3),(1)的问题很清楚,但我看不出(2)中的“暴露在铁锈中”与(1)中的区别,在(3)中,我不清楚为什么执行操作会导致问题……如果你问ManuallyDrop
实现是否不可靠,那么你应该遵循它的约定。如果您从第二个代码段中删除drop
(这与本合同明显矛盾),可能不会有问题-如果它也是UB,那么,好吧,这是因为ManuallyDrop
是lang项,即编译器的特殊情况。
pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
ptr::read(&slot.value)
}