在Rust借用检查器中发现11年历史的健全性缺陷
11 year old unsoundness bugs found in Rust borrow checker

原始链接: https://github.com/rust-lang/rust/issues/164250

```rust ## 概述 这段 Rust 代码展示了一个编译器未能捕获的**栈内存超范围使用(stack-use-after-scope)**缺陷,该缺陷会导致未定义行为。 代码定义了一个结构体 `Q`,其 `Drop` 实现会将内部的值移动到全局向量 `KEPT` 中(以 `Box` 类型存储)。在 `main` 函数中,创建了一个 `String` 类型的变量 `l`,并将引用 `&l` 传给了 `Q`。当 `q` 被丢弃时,该引用会被装箱并存入 `KEPT`。然而,`l` 本身会在其所在作用域结束时被丢弃,导致 `KEPT` 持有一个悬垂指针。 随后,一个新的字符串 `z` 被分配,并复用了相同的栈内存。当 `KEPT[0]` 被向下转型为 `&'static String` 并打印时,输出的却是 `z` 的内容(`"XXXX..."`),而非原始的 `l` ——这是一个典型的释放后使用(use-after-free)问题。 **预期结果:**编译器应拒绝编译此代码,因为将 `&l` 存储为 `&'static` 类型是不安全的。 **实际结果:**该程序在稳定版(≥1.85.0)及 nightly 版本上均可编译通过,并静默地产生错误输出。在 AddressSanitizer 下,程序会因 `stack-use-after-scope` 错误而崩溃,从而确认了内存安全违规。 ```

一篇 Hacker News 帖子介绍了在 Rust 借用检查器中发现的存在了十一年之久的漏洞。评论者讨论了 counterexamples.org 网站,该网站记录了类似的类型系统边界案例。一位用户解释了核心问题:一个具有自定义 `Drop` 实现的结构体可以访问非 `'static` 的引用,而类型系统却假设它是 `'static` 的,从而造成了一个漏洞。这个 bug 之所以长期存在,部分原因是自定义 `Drop` 实现在实践中相对少见,而且开发者很少手动编写与方差相关的代码。一些评论者对如此简单的例子在十多年间未被发现表示惊讶,而另一些人则认为这并不意外,因为 Rust 编译器中存在一系列已知的漏洞(以 "l-unsound" 标签跟踪)。讨论引发了关于 Rust 编译器中存在此类漏洞时是否还能真正称为内存安全的争论,有人认为实现缺陷不同于语言设计缺陷。还有人指出 Rust 缺乏正式的语言规范,使得 `rustc` 成为事实标准。共识倾向于承认没有哪种语言是完美的,尽管在实践中 Rust 仍然比 C/C++ 安全得多。
相关文章

原文

In the following code:

use std::sync::Mutex;
static KEPT: Mutex<Vec<Box<dyn std::any::Any + Send>>> = Mutex::new(Vec::new());
struct Q<T: 'static + Send>(Option<T>);
impl<T: 'static + Send> Drop for Q<T> {
    fn drop(&mut self) { if let Some(t) = self.0.take() { KEPT.lock().unwrap().push(Box::new(t)); } }
}
fn main() {
    {
        let l = String::from("hello world, this is long enough");
        let mut q = Q(None);
        q.0 = Some(&l);
    }
    let _z = String::from("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
    let k = KEPT.lock().unwrap();
    println!("{}", k[0].downcast_ref::<&'static String>().unwrap());
}

I expected to see this happen: program is not accepted

Instead, this happened: program compiles and prints XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. With asan, the program will crash with a AddressSanitizer: stack-use-after-scope

Meta

Issue on current nightly, and stables at least down to 1.85.0

Godbolt with asan: https://rust.godbolt.org/z/83MvfbKde
Godbolt without asan: https://rust.godbolt.org/z/GsGdqqMWe

联系我们 contact @ memedata.com