-   Notifications  You must be signed in to change notification settings 
- Fork 13.9k
Open
Labels
C-bugCategory: This is a bug.Category: This is a bug.F-arbitrary_self_types`#![feature(arbitrary_self_types)]``#![feature(arbitrary_self_types)]`F-derive_coerce_pointeeFeature: RFC 3621's oft-renamed implementationFeature: RFC 3621's oft-renamed implementationT-langRelevant to the language teamRelevant to the language teamT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
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
joseluis
Metadata
Metadata
Assignees
Labels
C-bugCategory: This is a bug.Category: This is a bug.F-arbitrary_self_types`#![feature(arbitrary_self_types)]``#![feature(arbitrary_self_types)]`F-derive_coerce_pointeeFeature: RFC 3621's oft-renamed implementationFeature: RFC 3621's oft-renamed implementationT-langRelevant to the language teamRelevant to the language teamT-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.