//@ known-bug: #112905 //@ check-pass // Classified as an issue with implied bounds: // https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 #![forbid(unsafe_code)] // No `unsafe!` #![feature(type_alias_impl_trait)] use std::any::Any; /// Anything covariant will do, for this demo. type T<'lt> = &'lt str; type F<'a, 'b> = impl 'static + Fn(T<'a>) -> T<'b>; fn helper<'a, 'b>(_: [&'b &'a (); 0]) -> F<'a, 'b> { |x: T<'a>| -> T<'b> { x } // this should *not* be `: 'static` } fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { let f: F<'a, 'a> = helper([]); let any = Box::new(f) as Box; let f: F<'a, 'static> = *any.downcast().unwrap_or_else(|_| unreachable!()); f(a) } fn main() { let r: T<'static> = { let local = String::from("..."); exploit(&local) }; // Since `r` now dangles, we can easily make the use-after-free // point to newly allocated memory! let _unrelated = String::from("UAF"); dbg!(r); // may print `UAF`! Run with `miri` to see the UB. }