rust-lang / rust-lang/rust

Unsoundness due to closure return value not being checked for WF

Open
#151,637 11 comments 0 reactions 1 assignee View on GitHub

@ShoyuVanilla is already working on this.

Since Feb 20, 2026.

A-borrow-checker A-closures A-lifetimes A-NLL C-bug I-unsound P-high T-compiler T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.