Skip to content

Commit 25acbbd

Browse files
committed
Auto merge of #127435 - GrigorenkoPV:tests-for-112905, r=cjgillot
Add tests for #112905 This is a part of #105107. Adds the tests from the OP in #112905.
2 parents c1e3f03 + 32294aa commit 25acbbd

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//@ known-bug: #112905
2+
//@ check-pass
3+
4+
// Classified as an issue with implied bounds:
5+
// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998
6+
7+
/// Note: this is sound! It's the "type witness" pattern (here, lt witness).
8+
mod some_lib {
9+
use super::T;
10+
11+
/// Invariant in `'a` and `'b` for soundness.
12+
pub struct LtEq<'a, 'b>(::std::marker::PhantomData<*mut Self>);
13+
14+
impl<'a, 'b> LtEq<'a, 'b> {
15+
pub fn new() -> LtEq<'a, 'a> {
16+
LtEq(<_>::default())
17+
}
18+
19+
pub fn eq(&self) -> impl 'static + Fn(T<'a>) -> T<'b> {
20+
|a| unsafe { ::std::mem::transmute::<T<'a>, T<'b>>(a) }
21+
}
22+
}
23+
}
24+
25+
use some_lib::LtEq;
26+
use std::{any::Any, cell::Cell};
27+
28+
/// Feel free to choose whatever you want, here.
29+
type T<'lt> = Cell<&'lt str>;
30+
31+
fn exploit<'a, 'b>(a: T<'a>) -> T<'b> {
32+
let f = LtEq::<'a, 'a>::new().eq();
33+
let any = Box::new(f) as Box<dyn Any>;
34+
35+
let new_f = None.map(LtEq::<'a, 'b>::eq);
36+
37+
fn downcast_a_to_type_of_new_f<F: 'static>(any: Box<dyn Any>, _: Option<F>) -> F {
38+
*any.downcast().unwrap_or_else(|_| unreachable!())
39+
}
40+
41+
let f = downcast_a_to_type_of_new_f(any, new_f);
42+
43+
f(a)
44+
}
45+
46+
fn main() {
47+
let r: T<'static> = {
48+
let local = String::from("…");
49+
let a: T<'_> = Cell::new(&local[..]);
50+
exploit(a)
51+
};
52+
dbg!(r.get());
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ known-bug: #112905
2+
//@ check-pass
3+
4+
// Classified as an issue with implied bounds:
5+
// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998
6+
7+
#![forbid(unsafe_code)] // No `unsafe!`
8+
#![feature(type_alias_impl_trait)]
9+
10+
use std::any::Any;
11+
12+
/// Anything covariant will do, for this demo.
13+
type T<'lt> = &'lt str;
14+
15+
type F<'a, 'b> = impl 'static + Fn(T<'a>) -> T<'b>;
16+
17+
fn helper<'a, 'b>(_: [&'b &'a (); 0]) -> F<'a, 'b> {
18+
|x: T<'a>| -> T<'b> { x } // this should *not* be `: 'static`
19+
}
20+
21+
fn exploit<'a, 'b>(a: T<'a>) -> T<'b> {
22+
let f: F<'a, 'a> = helper([]);
23+
let any = Box::new(f) as Box<dyn Any>;
24+
25+
let f: F<'a, 'static> = *any.downcast().unwrap_or_else(|_| unreachable!());
26+
27+
f(a)
28+
}
29+
30+
fn main() {
31+
let r: T<'static> = {
32+
let local = String::from("...");
33+
exploit(&local)
34+
};
35+
// Since `r` now dangles, we can easily make the use-after-free
36+
// point to newly allocated memory!
37+
let _unrelated = String::from("UAF");
38+
dbg!(r); // may print `UAF`! Run with `miri` to see the UB.
39+
}

0 commit comments

Comments
 (0)