Skip to content

Unsoundness due to closure return value not being checked for WF #151637

@theemathas

Description

@theemathas

This unsoundness is an exploitation of the weirdness in #123312. See also #148854 for a similar unsoundness.

The below code causes a use-after-free (segfault in my testing).

type Payload = Box<i32>;

trait StaticToStatic {
    fn static_to_static(self) -> &'static Payload where Self: 'static;
}
impl<'a> StaticToStatic for &'a Payload {
    fn static_to_static(self) -> &'static Payload where Self: 'static {
        self  // Legal. 'a must be 'static due to Self: 'static
    }
}

struct Wrap<T: StaticToStatic + 'static>(T);

trait ToStatic {
    fn to_static(self) -> &'static Payload;
}
impl<T: StaticToStatic> ToStatic for Wrap<T> {
    fn to_static(self) -> &'static Payload {
        self.0.static_to_static()  // Legal. T: 'static is implied by Wrap<T>
    }
}

// Trait to allow mentioning FnOnce without mentioning the return type directly
trait MyFnOnce {
    type MyOutput;
    fn my_call_once(self) -> Self::MyOutput;
}
impl<F: FnOnce() -> T, T> MyFnOnce for F {
    type MyOutput = T;
    fn my_call_once(self) -> T {
        self()
    }
}

fn call<F: MyFnOnce<MyOutput: ToStatic>>(f: F) -> &'static Payload {
    f.my_call_once().to_static()
}

fn extend<T: StaticToStatic>(x: T) -> &'static Payload {
    let c = move || {
        // Probably should be illegal, since Wrap requires T: 'static
        Wrap(x)
    };
    call(c)
}

fn main() {
    let x = Box::new(Box::new(1));
    let y = extend(&*x);
    drop(x);
    println!("{y}");  // segfaults
}

cc @lcnr @ShoyuVanilla

Meta

Reproducible on the playground with version 1.95.0-nightly (2026-01-24 f134bbc78dac04a17324)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-NLLArea: Non-lexical lifetimes (NLL)A-borrow-checkerArea: The borrow checkerA-closuresArea: Closures (`|…| { … }`)A-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Status

    open/unblocked

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions