为什么通过原始指针修改可变引用的值不会违反Rust的别名规则? [英] Why does modifying a mutable reference's value through a raw pointer not violate Rust's aliasing rules?

查看:104
本文介绍了为什么通过原始指针修改可变引用的值不会违反Rust的别名规则?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Rust的别名规则没有特别扎实的理解(从我听来并没有明确定义),但是我很难理解

I don't have a particularly solid understanding of Rust's aliasing rules (and from what I've heard they're not solidly defined), but I'm having trouble understanding what makes this code example in the std::slice documentation okay. I'll repeat it here:

let x = &mut [1, 2, 4];
let x_ptr = x.as_mut_ptr();

unsafe {
    for i in 0..x.len() {
        *x_ptr.offset(i as isize) += 2;
    }
}
assert_eq!(x, &[3, 4, 6]);

我在这里看到的问题是,作为&mut引用的x可以被编译器假定为唯一. x的内容通过x_ptr进行了修改,然后通过x进行了回读,我看不出编译器不能仅仅假设未修改x的原因,因为它从未被修改过通过仅有的现有&mut参考.

The problem I see here is that x, being an &mut reference, can be assumed to be unique by the compiler. The contents of x get modified through x_ptr, and then read back via x, and I see no reason why the compiler couldn't just assume that x hadn't been modified, since it was never modified through the only existing &mut reference.

那么,我在这里想念什么?

So, what am I missing here?

  • 即使通常允许假定&mut T 从不为另一个&mut T别名,编译器是否需要假定*mut T可以为&mut T别名?

  • Is the compiler required to assume that *mut T may alias &mut T, even though it's normally allowed to assume that &mut T never aliases another &mut T?

unsafe块是否充当某种混叠屏障,编译器认为其中的代码可能已修改范围内的任何内容?

Does the unsafe block act as some sort of aliasing barrier, where the compiler assumes that code inside it may have modified anything in scope?

此代码示例是否已损坏?

Is this code example broken?

如果有某种稳定的规则可以使该示例正常运行,那到底是什么呢?程度如何?我应该为别名假说打破unsafe Rust代码中的随机事物担心多少?

If there is some kind of stable rule that makes this example okay, what exactly is it? What is its extent? How much should I worry about aliasing assumptions breaking random things in unsafe Rust code?

推荐答案

免责声明:尚无正式的内存模型. 1

首先,我要解决:

我在这里看到的问题是,作为&mut引用的x可以被编译器假定为唯一.

The problem I see here is that x, being an &mut reference, can be assumed to be unique by the compiler.

是的,不是. x如果不借用,只能被认为是唯一的 ,这是一个重要的区别:

Yes... and no. x can only be assumed to be unique if not borrowed, an important distinction:

fn doit(x: &mut T) {
    let y = &mut *x;
    //  x is re-borrowed at this point.
}

因此,目前,我将假设从x派生指针将在某种意义上暂时借用" x.

Therefore, currently, I would work with the assumption that deriving a pointer from x will temporarily "borrow" x in some sense.

这当然是在缺少正式模型的情况下令人讨厌的事情,这也是rustc编译器在使用别名优化时还不太积极的部分原因:直到定义了正式模型,并检查代码是否匹配它,优化必须保守.

This is all wishy washy in the absence of a formal model, of course, and part of the reason why the rustc compiler is not too aggressive with aliasing optimizations yet: until a formal model is defined, and code is checked to match it, optimizations have to be conservative.

1 RustBelt项目是关于为Rust建立经过正式验证的内存模型的. Ralf Jung的最新消息是关于堆叠借阅模型.

来自Ralf(评论):上例中的关键点是从xx_ptr并再次回到x的明确转移.因此,从某种意义上讲,x_ptr是有范围的借用.如果用法转到xx_ptr,回到x再回到x_ptr,则后者将为未定义行为":

From Ralf (comments): the key point in the above example is that there is a clear transfer from x to x_ptr and back to x again. So the x_ptr is a scoped borrow in a sense. Should the usage go x, x_ptr, back to x and back to x_ptr, then the latter would be Undefined Behavior:

fn main() {
    let x = &mut [1, 2, 4];
    let x_ptr = x.as_mut_ptr(); // x_ptr borrows the right to mutate

    unsafe {
        for i in 0..x.len() {
            *x_ptr.offset(i as isize) += 2; // Fine use of raw pointer.
        }
    }
    assert_eq!(x, &[3, 4, 6]);  // x is back in charge, x_ptr invalidated.

    unsafe { *x_ptr += 1; }     // BÄM! Used no-longer-valid raw pointer.
}

这篇关于为什么通过原始指针修改可变引用的值不会违反Rust的别名规则?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆