Description
The following code compiles, since February nightlies and on stable version 1.69 (no older stable versions are affected). (playground):
struct Spooky<'b> {
owned: String,
borrowed: &'b str,
}
impl<'b> Spooky<'b> {
fn create_self_reference<'a>(&'a mut self) {
let mut closure = || {
let borrow: &'a String = &self.owned;
self.borrowed = borrow;
};
closure();
}
}
fn main() {
let mut spooky: Spooky<'static> = Spooky {
owned: "Hello".to_string(),
borrowed: "static string, initially",
};
spooky.create_self_reference();
std::mem::take(&mut spooky.owned);
for _ in 0..1000 {
let _ = format!("askld");
}
println!("{}", spooky.borrowed);
}
This is clearly a use-after-free. On my Linux machine it prints a garbage string. It should not compile at all, the error should be basically the same as if you didn't wrap the offending lines in a closure. The issue still occurs with self.borrowed = &self.owned
, the annotations are just for clarity.
The problem was introduced in #107969.
Hat tip to @ladecaz for writing the cursed code that got us here.
cargo-bisect-rustc results
searched nightlies: from nightly-2021-04-25 to nightly-2023-05-29
regressed nightly: nightly-2023-02-21
searched commit range: 7aa413d...5243ea5
regressed commit: e7eaed2
bisected with cargo-bisect-rustc v0.6.6
Host triple: x86_64-unknown-linux-gnu
Reproduce with:
cargo bisect-rustc --start=2021-04-25 --regress success