编译器通过禁止分配给借用的值来防止什么灾难?
What disaster does the compiler prevent by disallowing assigning to a borrowed value?
来自 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();
编译器不允许这样做:
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
但假设确实如此;
怎么样
Now p
is a &String
, pointing at memory that is an int of our choosing!
是坏事吗?
让我们为涉及的类型做一个内存布局。 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
处的值.在示例中,存储在值中的 "address" 现在将指向任意位置 (0xDEADBEEF
)。如果我们尝试使用 "string",我们将开始读取不太可能对应于 UTF-8 数据的内存字节。
None 这是学术性的,这种问题可能发生在格式良好的 C 程序中。在good情况下,程序会崩溃。在糟糕的情况下,您可能会在不应该的情况下读取程序中的数据。甚至可以注入 shellcode,然后让攻击者能够 运行 代码 他们 在您的程序中编写。
请注意,上面的内存布局非常简化,而实际String
更大更复杂。
来自 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();
编译器不允许这样做:
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
但假设确实如此;
怎么样Now
p
is a&String
, pointing at memory that is an int of our choosing!
是坏事吗?
让我们为涉及的类型做一个内存布局。 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
处的值.在示例中,存储在值中的 "address" 现在将指向任意位置 (0xDEADBEEF
)。如果我们尝试使用 "string",我们将开始读取不太可能对应于 UTF-8 数据的内存字节。
None 这是学术性的,这种问题可能发生在格式良好的 C 程序中。在good情况下,程序会崩溃。在糟糕的情况下,您可能会在不应该的情况下读取程序中的数据。甚至可以注入 shellcode,然后让攻击者能够 运行 代码 他们 在您的程序中编写。
请注意,上面的内存布局非常简化,而实际String
更大更复杂。