Skip to content

Tracking Issue for breaking lifetime changing raw pointer casts of trait objects #141402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
BoxyUwU opened this issue May 22, 2025 · 0 comments
Labels
A-dyn-trait Area: trait objects, vtable layout A-raw-pointers Area: raw pointers, MaybeUninit, NonNull C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-arbitrary_self_types `#![feature(arbitrary_self_types)]` F-derive_coerce_pointee Feature: RFC 3621's oft-renamed implementation T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@BoxyUwU
Copy link
Member

BoxyUwU commented May 22, 2025

This is the tracking issue for the breaking change made in #136776 The goal of this page is describe why this change was made and how you can fix code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made.

What is the warning for?

As part of stabilizing the arbitrary_self_types and derive_coerce_pointee we needed to change what raw pointer casts are legal. Specifically, casting *const dyn Trait + 'a to *const dyn Trait + 'b where it is not able to be proven that 'a outlives 'b has become an error.

Why was this change made?

Casting the lifetime bound on trait objects can invalidate the VTable for the trait object allowing for dispatching to methods that should not be callable. When a trait method has a where Self: 'a bound, casting the lifetime bound on a trait object may cause the method to go from uncallable to callable.

Example

#![forbid(unsafe_code)]
#![feature(arbitrary_self_types, derive_coerce_pointee)]

use std::any::TypeId;
use std::marker::{CoercePointee, 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 {
    let ptr = SelfPtr(
        // This line no longer compiles
        &PhantomData::<T> as *const (dyn GetTypeId + '_) as *const (dyn GetTypeId + 'static),
    );
    ptr.get_type_id()
}

Migration

Existing code can be trivially migrated by converting the offending raw pointer cast to a lifetime affecting transmute. See metrics-rs/metrics#564 as an example of how such a migration can be accomplished. It's advised to only do so if actually sure that extending the lifetime of the trait object is sound.

Related Links

@BoxyUwU BoxyUwU added T-lang Relevant to the language team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-arbitrary_self_types `#![feature(arbitrary_self_types)]` A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-dyn-trait Area: trait objects, vtable layout F-derive_coerce_pointee Feature: RFC 3621's oft-renamed implementation labels May 22, 2025
@BoxyUwU BoxyUwU pinned this issue May 22, 2025
@BoxyUwU BoxyUwU unpinned this issue May 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-dyn-trait Area: trait objects, vtable layout A-raw-pointers Area: raw pointers, MaybeUninit, NonNull C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-arbitrary_self_types `#![feature(arbitrary_self_types)]` F-derive_coerce_pointee Feature: RFC 3621's oft-renamed implementation T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

1 participant