54 lines
1.3 KiB
Rust
54 lines
1.3 KiB
Rust
//@ known-bug: #112905
|
|
//@ check-pass
|
|
|
|
// Classified as an issue with implied bounds:
|
|
// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998
|
|
|
|
/// Note: this is sound! It's the "type witness" pattern (here, lt witness).
|
|
mod some_lib {
|
|
use super::T;
|
|
|
|
/// Invariant in `'a` and `'b` for soundness.
|
|
pub struct LtEq<'a, 'b>(::std::marker::PhantomData<*mut Self>);
|
|
|
|
impl<'a, 'b> LtEq<'a, 'b> {
|
|
pub fn new() -> LtEq<'a, 'a> {
|
|
LtEq(<_>::default())
|
|
}
|
|
|
|
pub fn eq(&self) -> impl 'static + Fn(T<'a>) -> T<'b> {
|
|
|a| unsafe { ::std::mem::transmute::<T<'a>, T<'b>>(a) }
|
|
}
|
|
}
|
|
}
|
|
|
|
use some_lib::LtEq;
|
|
use std::{any::Any, cell::Cell};
|
|
|
|
/// Feel free to choose whatever you want, here.
|
|
type T<'lt> = Cell<&'lt str>;
|
|
|
|
fn exploit<'a, 'b>(a: T<'a>) -> T<'b> {
|
|
let f = LtEq::<'a, 'a>::new().eq();
|
|
let any = Box::new(f) as Box<dyn Any>;
|
|
|
|
let new_f = None.map(LtEq::<'a, 'b>::eq);
|
|
|
|
fn downcast_a_to_type_of_new_f<F: 'static>(any: Box<dyn Any>, _: Option<F>) -> F {
|
|
*any.downcast().unwrap_or_else(|_| unreachable!())
|
|
}
|
|
|
|
let f = downcast_a_to_type_of_new_f(any, new_f);
|
|
|
|
f(a)
|
|
}
|
|
|
|
fn main() {
|
|
let r: T<'static> = {
|
|
let local = String::from("…");
|
|
let a: T<'_> = Cell::new(&local[..]);
|
|
exploit(a)
|
|
};
|
|
dbg!(r.get());
|
|
}
|