Open
Description
Here's an example by @steffahn:
#![forbid(unsafe_code)]
#![feature(arbitrary_self_types, derive_coerce_pointee)]
use std::any::TypeId;
use std::marker::CoercePointee;
use std::marker::PhantomData;
#[derive(CoercePointee)]
#[repr(transparent)]
struct SelfPtr<T: ?Sized>(*const T);
impl<T: ?Sized> std::ops::Deref for SelfPtr<T> {
type Target = T;
fn deref(&self) -> &T {
panic!("please don't call me, I just want the `Receiver` impl!");
}
}
trait GetTypeId {
fn get_type_id(self: SelfPtr<Self>) -> TypeId
where
Self: 'static;
}
impl<T: ?Sized> GetTypeId for PhantomData<T> {
fn get_type_id(self: SelfPtr<Self>) -> TypeId
where
Self: 'static,
{
TypeId::of::<T>()
}
}
// no `T: 'static` bound 🐈⬛ necessary
fn type_id_of<T: ?Sized>() -> TypeId {
SelfPtr(&PhantomData::<T> as *const (dyn GetTypeId + '_) as *const (dyn GetTypeId + 'static)).get_type_id()
}
fn type_id_of_val<T: ?Sized>(_: &T) -> TypeId {
type_id_of::<T>()
}
fn main() {
let mut x = 1234;
let reference = &mut x;
let tid_of_ref = type_id_of_val(&reference);
let closure = || *reference += 1;
let tid_of_closure = type_id_of_val(&closure);
dbg!(tid_of_ref, tid_of_closure);
}
The double as *const dyn GetTypeId as *const dyn GetTypeId
is necessary; the second as
changes the lifetime something short-lived to 'static
. That means we call get_type_id
on a type that does not satisfy Self: 'static
.
@BoxyUwU has a similar example:
#![feature(arbitrary_self_types, derive_coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct MyPtr<T: ?Sized>(*const T);
use std::ops::Receiver;
impl<T: ?Sized> Receiver for MyPtr<T> {
type Target = T;
}
trait Trait {
fn foo(self: MyPtr<Self>)
where
Self: Send;
}
impl Trait for *mut () {
fn foo(self: MyPtr<Self>) {
unreachable!()
}
}
fn main() {
let a = 0x1 as *const *mut ();
let a = a as *const dyn Trait as *const (dyn Trait + Send);
MyPtr(a).foo();
}
Boxy's example is mitigated by a FCW lint. However, the lifetime example doesn't trigger a lint, and while the code above is "fine", we should at least have a good idea for why this cannot cause UB in other ways. (My gut feeling is that this can cause UB but I haven't tried.)
Cc @rust-lang/types