Skip to content

Commit 9c44157

Browse files
authored
Unrolled build for #156170
Rollup merge of #156170 - inq:add-known-bug-test-144442, r=JohnTitor add known-bug test for coroutine 'static-yields-non-'static unsoundness (#144442) Add a `known-bug` regression test for [#144442 ("Unsoundness due to 'static coroutines that yield non-'static values").](#144442) Existing known-bug tests: ``` - tests/ui/closures/static-closures-with-nonstatic-return.rs - tests/ui/implied-bounds/dyn-erasure-tait.rs - tests/ui/implied-bounds/dyn-erasure-no-tait.rs ``` Verified in Darwin: running the compiled binary segfaults on current main, so the bug is still present.
2 parents e95e732 + 227a289 commit 9c44157

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//@ check-pass
2+
//@ known-bug: #144442
3+
4+
// Same family as #84366 / #112905: a coroutine that yields a non-`'static`
5+
// reference is wrongly `: 'static`, allowing a `Box<dyn Any>` downcast to
6+
// transmute between distinct lifetime substitutions and produce a UAF.
7+
8+
#![forbid(unsafe_code)] // No `unsafe!`
9+
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
10+
11+
use std::any::Any;
12+
use std::cell::RefCell;
13+
use std::ops::{Coroutine, CoroutineState};
14+
use std::pin::Pin;
15+
use std::rc::Rc;
16+
17+
type Payload = Box<i32>;
18+
19+
fn make_coro<'a>()
20+
-> impl Coroutine<Yield = Rc<RefCell<Option<&'a Payload>>>, Return = ()> + 'static {
21+
#[coroutine]
22+
|| {
23+
let storage: Rc<RefCell<Option<&'a Payload>>> = Rc::new(RefCell::new(None));
24+
yield storage.clone();
25+
yield storage;
26+
}
27+
}
28+
29+
pub fn expand<'a>(payload: &'a Payload) -> &'static Payload {
30+
let mut coro1 = Box::pin(make_coro::<'a>());
31+
let coro2 = make_coro::<'static>();
32+
let CoroutineState::Yielded(storage) = coro1.as_mut().resume(()) else {
33+
panic!()
34+
};
35+
*storage.borrow_mut() = Some(payload);
36+
extract(coro1, coro2)
37+
}
38+
39+
fn extract<
40+
'a,
41+
F: Coroutine<Yield = Rc<RefCell<Option<&'a Payload>>>, Return = ()> + 'static,
42+
G: Coroutine<Yield = Rc<RefCell<Option<&'static Payload>>>, Return = ()> + 'static,
43+
>(
44+
x: Pin<Box<F>>,
45+
_: G,
46+
) -> &'static Payload {
47+
let mut g: Pin<Box<G>> = *(Box::new(x) as Box<dyn Any>).downcast().unwrap();
48+
let CoroutineState::Yielded(storage) = g.as_mut().resume(()) else {
49+
panic!()
50+
};
51+
let payload = storage.borrow().unwrap();
52+
payload
53+
}
54+
55+
fn main() {
56+
let x = Box::new(Box::new(1i32));
57+
let y = expand(&x);
58+
drop(x);
59+
println!("{y}"); // Segfaults — UAF without `unsafe`.
60+
}

0 commit comments

Comments
 (0)