← Back to Index

11 year old unsoundness bugs found in Rust borrow checker

Source: Hacker News: Front Page
Published: October 13, 2026 at 3:27 AM

I think unification just generally doesn't check lifetime bounds of the type. Example with regular unification, without field assignment:

struct Q<T: Copy, F: FnMut(T)>(T, F);

impl<T: Copy, F: FnMut(T)> Drop for Q<T, F> {
    fn drop(&mut self) {
        self.1(self.0)
    }
}

type T = Vec<Vec<i32>>;

fn main() {
    let long = Box::leak(Box::new(T::new())) as &'static T;
    {
        let local: T = vec![vec![1]];

        // item type is Q<&'local T, fn(&'static T)>, which is ill-formed
        let mut unified = [
            Q(
                long,
                (|s: &'static T| {
                    std::thread::spawn(move || {
                        println!("{s:?}");
                    });
                }) as fn(&'static T),
            ),
            Q(&local, (|_: &T| {}) as fn(&T)),
        ];

        let [l, r] = &mut unified;
        std::mem::swap(&mut l.0, &mut r.0);
    }

    std::thread::sleep_ms(1000);
}

Reacted by 9291Sam, Bee4Queer, Maple, Thefool and T-256