编译器不允许分配借入的值可以防止什么灾难? [英] What disaster does the compiler prevent by disallowing assigning to a borrowed value?

查看:95
本文介绍了编译器不允许分配借入的值可以防止什么灾难?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自在Rust中编程(PDF):

 #[派生(调试)] 
枚举IntOrString {
I(isize),
S(String),
}

fn destroy_enum(){
let mut s = IntOrString :: S(String :: new());
match s {
IntOrString :: I(_)=> (),
IntOrString :: S(ref p)=> {
s = IntOrString :: I(0xdeadbeef);
//现在p是& String,指向内存
//这是我们选择的int!
}
}
}

destroy_enum();

编译器不允许这样做:

 错误[E0506]:由于借入了
,因此无法分配给s。 src / main.rs:13:17
|
12 | IntOrString :: S(ref p)=> {
| -----在这里借用 s
13 | s = IntOrString :: I(0xdeadbeef);
|
<^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ / pre>

但假设确实如此;


现在 p & ; String ,指向内存,这是我们选择的一个整数!


是一件坏事吗?

解决方案

让我们为涉及的类型组成一个内存布局。 IntOrString 将有一个字节来确定它是哪个变体( 0 =数字, 1 =字符串),后跟4个字节,这些字节可以是数字,也可以是一组UTF-8字符开头的地址。



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



使用匹配臂 IntOrString :: S(ref p)时, p 将被设置为值 0x101 -这是对该值的引用,该值从0x101开始。当您尝试使用 p 时,处理器将转到地址 0x101 ,读取值(地址),然后从该地址读取数据。



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



这些都不是学术性的,这种确切类型的问题可能会在格式良好的C程序中发生。在良好的情况下,程序将崩溃。在严重的情况下,可能会在您不应该使用的程序中读取数据。甚至有可能注入shellcode,然后使攻击者能够运行程序中编写的代码他们






请注意,上面的内存布局非常简化,实际的 String 更大且更复杂。


An example from Programming in Rust (PDF):

#[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();

The compiler does not allow this:

error[E0506]: cannot assign to `s` because it is borrowed
  --> src/main.rs:13:17
   |
12 |             IntOrString::S(ref p) => {
   |                            ----- borrow of `s` occurs here
13 |                 s = IntOrString::I(0xdeadbeef);
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `s` occurs here

But suppose it did; how is it that

Now p is a &String, pointing at memory that is an int of our choosing!

is a bad thing?

解决方案

Let's make up a memory layout for the types involved. IntOrString will have one byte to determine which variant it is (0 = number, 1 = string), followed by 4 bytes that will either be a number or the address to the beginning of a set of UTF-8 characters.

Let's allocate s in memory at 0x100. The variant is at 0x100 and the value is at 0x101, 0x102, 0x103, 0x104. Additionally, let's say that the contents of the value is the pointer 0xABCD; this is where the bytes of the string live.

When the match arm IntOrString::S(ref p) is used, p will be set to the value 0x101 - it's a reference to the value and the value starts at 0x101. When you try to use p, the processor will go to the address 0x101, read the value (an address), and then read the data from that address.

If the compiler allowed you to change s at this point, then the new bytes of the new data would replace the value stored at 0x101. In the example, the "address" stored at the value would now point to somewhere arbitrary (0xDEADBEEF). If we tried to use the "string", we'd start reading bytes of memory that are highly unlikely to correspond to UTF-8 data.

None of this is academic, this exact kind of problem can occur in a well-formed C program. In the good cases, the program will crash. In bad cases, it's possible to read data in the program you aren't supposed to. It's even possible to inject shellcode that then gives an attacker the ability to run code they wrote inside your program.


Note that the memory layout above is very simplified, and an actual String is larger and more complicated.

这篇关于编译器不允许分配借入的值可以防止什么灾难?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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