-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Description
This is similar to #112905 and #84366, but it seems different enough so I'm filing a new issue.
The following code causes use-after-free:
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::any::Any;
use std::cell::RefCell;
use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;
use std::rc::Rc;
type Payload = Box<i32>;
fn make_coro<'a>() -> impl Coroutine<Yield = Rc<RefCell<Option<&'a Payload>>>, Return = ()> + 'static
{
#[coroutine]
|| {
let storage: Rc<RefCell<Option<&'a Payload>>> = Rc::new(RefCell::new(None));
yield storage.clone();
yield storage;
}
}
pub fn expand<'a>(payload: &'a Payload) -> &'static Payload {
let mut coro1 = Box::pin(make_coro::<'a>());
let coro2 = make_coro::<'static>();
let CoroutineState::Yielded(storage) = coro1.as_mut().resume(()) else {
panic!()
};
*storage.borrow_mut() = Some(payload);
extract(coro1, coro2)
}
fn extract<
'a,
F: Coroutine<Yield = Rc<RefCell<Option<&'a Payload>>>, Return = ()> + 'static,
G: Coroutine<Yield = Rc<RefCell<Option<&'static Payload>>>, Return = ()> + 'static,
>(
x: Pin<Box<F>>,
_: G,
) -> &'static Payload {
let mut g: Pin<Box<G>> = *(Box::new(x) as Box<dyn Any>).downcast().unwrap();
let CoroutineState::Yielded(storage) = g.as_mut().resume(()) else {
panic!()
};
storage.borrow().unwrap()
}
fn main() {
let x = Box::new(Box::new(1i32));
let y = expand(&x);
drop(x);
println!("{y}"); // Segfaults
}
The root of the unsoundness here is that the coroutine returned from make_coro
mentions the lifetime 'a
in the body, so the coroutine should not be 'static
. Yet, rust allows it to be 'static
anyway. This allows extract
to transmute the coroutine from one lifetime to another using Any
. The coroutine yields the storage for the payload twice, once before the transmute, and once after. As a result, the storage is treated as two different lifetimes, allowing lifetime extension on arbitrary types.
@rustbot labels +I-unsound +requires-nightly +A-coroutines +F-coroutines +A-lifetimes +T-types
Meta
Reproduces on the playground with version 1.90.0-nightly (2025-07-24 b56aaec52bc0fa35591a)