|
| 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 | +} |
0 commit comments