Rust 编译器通过禁止赋值给借来的值来防止什么灾难?

Rust 编译器通过禁止赋值给借来的值来防止什么灾难?,rust,borrowing,Rust,Borrowing,例如: 编译器不允许这样做: 错误[E0506]:无法分配给's',因为它是借用的 ->src/main.rs:13:17 | 12 | IntOrString::Sref p=>{ |---s的借词出现在这里 13 | s=IntOrString::I0xdeadbeef; |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^此处发生借来的's'的赋值 但是,假设是这样,那是怎么回事 现在p是一个&字符串,指向内存,这是我们选择的int 是一件坏事吗?让我们为所涉及

例如:

编译器不允许这样做:

错误[E0506]:无法分配给's',因为它是借用的 ->src/main.rs:13:17 | 12 | IntOrString::Sref p=>{ |---s的借词出现在这里 13 | s=IntOrString::I0xdeadbeef; |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^此处发生借来的's'的赋值 但是,假设是这样,那是怎么回事

现在p是一个&字符串,指向内存,这是我们选择的int


是一件坏事吗?

让我们为所涉及的类型建立一个内存布局。IntOrString将有一个字节来确定它是0=数字、1=字符串的变量,然后是4个字节,这些字节将是一个数字或一组UTF-8字符开头的地址

让我们在内存中的0x100处分配s。变量在0x100处,值在0x101、0x102、0x103、0x104处。此外,假设值的内容是指针0xABCD;这是字符串的字节所在位置

当使用match arm IntOrString::Sref p时,p将被设置为值0x101-它是对该值的引用,该值从0x101开始。当您尝试使用p时,处理器将转到地址0x101,从地址读取该值,然后从该地址读取数据

如果编译器允许您在此时更改,则新数据的新字节将替换存储在0x101处的值。在本例中,存储在该值处的地址现在将指向任意的0xDEADBEEF。如果我们尝试使用字符串,我们将开始读取极不可能与UTF-8 da对应的内存字节助教

所有这些都不是学术性的,这种问题可能发生在格式良好的C程序中。在好的情况下,程序会崩溃。在坏的情况下,有可能读取程序中不应该读取的数据。甚至有可能注入外壳代码,使攻击者能够运行他们在程序中编写的代码


请注意,上面的内存布局非常简单,实际字符串更大、更复杂。

让我们为所涉及的类型组成一个内存布局。IntOrString将有一个字节来确定哪个变量是0=number,1=String,然后是4个字节,它们将是一个数字或一组o开头的地址f UTF-8个字符

让我们在内存中的0x100处分配s。变量在0x100处,值在0x101、0x102、0x103、0x104处。此外,假设值的内容是指针0xABCD;这是字符串的字节所在位置

当使用match arm IntOrString::Sref p时,p将被设置为值0x101-它是对该值的引用,该值从0x101开始。当您尝试使用p时,处理器将转到地址0x101,从地址读取该值,然后从该地址读取数据

如果编译器允许您在此时更改,则新数据的新字节将替换存储在0x101处的值。在本例中,存储在该值处的地址现在将指向任意的0xDEADBEEF。如果我们尝试使用字符串,我们将开始读取极不可能与UTF-8 da对应的内存字节助教

所有这些都不是学术性的,这种问题可能发生在格式良好的C程序中。在好的情况下,程序会崩溃。在坏的情况下,有可能读取程序中不应该读取的数据。甚至有可能注入外壳代码,使攻击者能够运行他们在程序中编写的代码


请注意,上面的内存布局非常简化,而实际字符串更大、更复杂。

我对您的要求感到非常困惑。正如您所注意的,编译器阻止编译此代码。注释指的是如果编译器允许,可能会发生的情况,但由于编译器不允许,因此无所谓uld说现在p包含我的电话号码和中奖彩票号码,并且同样有效。我只是想了解编译器阻止了什么灾难的发生。是的,实际上这并不重要,但洞察力仍然很有价值。我对你的问题感到非常困惑。正如你所注意到的,编译器阻止了这段代码的编译。不是吗他的评论是指如果编译器允许的话可能会发生什么,但既然编译器不允许,那就没关系了。评论可以说现在p包含了我的电话号码和中奖彩票号码,并且同样有效。我只想了解编译器阻止了什么灾难的发生。是的,实际上没关系,但是e洞察仍然很有价值。
#[derive(Debug)]
enum IntOrString {
    I(isize),
    S(String),
}

fn corrupt_enum() {
    let mut s = IntOrString::S(String::new());
    match s {
        IntOrString::I(_) => (),
        IntOrString::S(ref p) => {
            s = IntOrString::I(0xdeadbeef);
            // Now p is a &String, pointing at memory
            // that is an int of our choosing!
        }
    }
}

corrupt_enum();