然而实际发生的是:程序编译通过并打印 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。如果启用 asan,程序会崩溃并报错 AddressSanitizer: stack-use-after-scope。
该问题在当前 nightly 版本以及至少低至 1.85.0 的 stable 版本上均可复现。
启用 asan 的 Godbolt 在线演示:https://rust.godbolt.org/z/83MvfbKde
未启用 asan 的 Godbolt 在线演示:https://rust.godbolt.org/z/GsGdqqMWe
表情回应功能目前不可用
动态
- jsnell 添加了 C-bug 标签(类别:这是一个 bug)(2026 年 10 月 13 日)
- rustbot 添加了 needs-triage 标签(该 issue 可能需要分诊,处理完成后移除。详见 forge.rust-lang.org/release/issue-triaging)(2026 年 10 月 13 日)
- theemathas 添加了 I-unsound 标签(问题:健全性漏洞,属于最严重的 bug 类型,参见:https://en.wikipedia.org/wiki/Soundness)(2026 年 10 月 13 日)
- rustbot 添加了 I-prioritize 标签(该 issue 需要团队成员评估影响,之后将被 P-{low,medium,high,critical} 取代)(2026 年 10 月 13 日)
- theemathas 添加了 A-borrow-checker 标签(领域:借用检查器)和 T-types 标签(与类型团队相关,由其审查并决定该 PR/issue 的处理),并移除了 needs-triage 标签(2026 年 10 月 13 日)
theemathas 于 2026 年 10 月 13 日评论
(由贡献者 theemathas 最后编辑)
健全性漏洞的核心:
struct Q<T: 'static>(Option<T>);
impl<T: 'static> Drop for Q<T> {
fn drop(&mut self) {
// 这里的代码可以访问一个非 'static 的 &String
// 但却假定它是一个 &'static String
}
}
fn main() {
let l = String::new();
let mut q = Q(None);
q.0 = Some(&l);
}
👀 已有 15 人以此回应:Daniel Vogelbacher、Serhiy、BioTomateDE、Timur Tugushev、palapapa、Ori Yadid、SeniorMars、dzmitry-lahoda、Til、Marco Quinten 等 15 人
- theemathas 添加了 A-destructors 标签(领域:析构函数(
Drop等))(2026 年 10 月 13 日) - rustbot 移除了 I-prioritize 标签(2026 年 10 月 13 日)
- rustbot 添加了 P-critical 标签(关键优先级)(2026 年 10 月 13 日)
theemathas 于 2026 年 10 月 13 日评论
(由贡献者 theemathas 最后编辑)
我这个版本的代码从 1.18.0(2017 年)起就能编译通过。
在此之前怎么可能一直没被发现???
struct MyType<'a, 'b: 'a, 'c>(&'c mut &'a str, &'b str);
impl<'a, 'b: 'a, 'c> Drop for MyType<'a, 'b, 'c> {
fn drop(&mut self) {
*self.0 = self.1;
}
}
fn main() {
let mut me_out = "rarw";
{
let l = String::from("some cool string");
let mut q = MyType(&mut me_out, "");
q.1 = &l;
}
println!("me_out: {me_out}");
}
🚀 已有 3 人以此回应:dzmitry-lahoda、Martijn Gribnau、Dale Weiler
- 另有 4 条动态
- 加载更多
- theemathas 于 2026 年 10 月 13 日的另一条评论(因过时被隐藏,展开评论)
maxdexh 于 2026 年 10 月 13 日评论
(由成员 maxdexh 最后编辑)
另一个自 1.4 起就会段错误/打印已释放内存的版本:
struct Q<T, F: FnMut(&T)>(Option<T>, F);
impl<T, F: FnMut(&T)> Drop for Q<T, F> {
fn drop(&mut self) {
self.1(self.0.as_ref().unwrap())
}
}
fn main() {
let mut out: Option<&'static _> = None;
{
let l = vec![vec![1]];
let mut q = Q(None, |s| {
out = Some(*s);
});
q.0 = Some(&l);
}
println!("{:?}", out);
}
- lcnr 修改了标题:从「struct’s
T: 'staticbound bypassed via covariant field assignment」改为「struct’s lifetime requirements can be bypassed via covariant field assignment」(2026 年 10 月 13 日) - maxdexh 添加了 A-lifetimes 标签(领域:生命周期 / regions)和 A-variance 标签(领域:型变,参见 https://doc.rust-lang.org/nomicon/subtyping.html)(2026 年 10 月 13 日)
theemathas 于 2026 年 10 月 13 日评论
(由贡献者 theemathas 最后编辑)
再来一个版本。我觉得这个版本可能是最容易理解的。
use std::time::Duration;
use std::thread;
struct Q<'a: 'static>(Option<&'a String>);
impl<'a: 'static> Drop for Q<'a> {
fn drop(&mut self) {
// 这里的代码可以访问一个非 'static 的 &String
// 但却假定它是一个 &'static String
let wrong: &'static String = self.0.unwrap();
thread::spawn(move || {
thread::sleep(Duration::from_secs(1));
println!("{}", wrong);
});
}
}
fn main() {
{
let l = String::from("abc");
let mut q = Q(None);
q.0 = Some(&l); // q.0 本应是 &'static String,但我们赋给它的是一个非 'static 的 &String
}
thread::sleep(Duration::from_secs(2));
}
👍 已有 2 人以此回应:Marek Šimek、Christopher Knight
👀 已有 1 人以此回应:Filip Dobrosavljević
maxdexh 于 2026 年 10 月 13 日评论
(由成员 maxdexh 最后编辑)
我认为统一(unification)过程通常根本不会检查类型的生命周期约束。下面是一个通过统一时强制转换触发问题的例子(不涉及字段赋值):