Skip to content

Tracking issue for stabilizing Error::type_id #60784

Description

@alexcrichton

View all comments

Updated Issue

This is a tracking issue for stabilizing the functionality of Error::type_id somehow. The subject of a historical security advisory the API was recently changed to prevent memory unsafety issues on all channels including nightly. The functionality, however, is still unstable, so we should stabilize it at some point!

Original issue.

Reported by @seanmonstar to the security mailing list recently, it was discovered that the recent stabilization of Error::type_id in Rust 1.34.0 is actually not memory safe. Described in a recent security announcement the stabilization of Error::type_id has been reverted for stable, beta, and master.

This leaves us, however, with the question of what to do about this API? Error::type_id has been present since the inception of the Error trait, all the way back to 1.0.0. It's unstable, however, and is pretty rare as well to have a manual implementation of the type_id function. Despite this we would ideally still like a path to stability which includes safety at some point.

This tracking issue is intended to serve as a location to discuss this issue and determine the best way forward to fully removing Error::type_id (so even nightly users are not affected by this memory safety issue) and having a stable mechanism for the functionality.

Activity

  1. added
    C-bugCategory: This is a bug.
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    T-libs-api[DEPRECATED; DO NOT USE]
    on May 13, 2019
  2. Centril commented on May 13, 2019

    @Centril
    Contributor

    Here's an unbaked thought: Can we make an extension unsafe trait ErrorTypeIdExt to Error, seal that extension trait (meaning that users cannot implement it), and then provide a blanket implementation for Error?

  3. crlf0710 commented on May 13, 2019

    @crlf0710
    Member

    I think my unbaked idea is not implementable in current Rust:

    trait Error {
       ...
       fn as_dyn_any(&self) -> &dyn Any where Self: 'static { self as _ }
       fn as_mut_dyn_any(&mut self) -> &mut dyn Any where Self: 'static { self as _ }
    }
    

    The only problem is we can't add a "where Self:Sized" bound to the "{ self as _ }" part.

  4. SimonSapin commented on May 13, 2019

    @SimonSapin
    Contributor

    It’s tempting to make Any a super-trait of Error, and rely on Any::type_id. This would be sound because Any already has a blanket impl that covers every possible impl, so it cannot be overridden.

    However Any requires 'static but Error doesn’t (only its TypeId-related methods do), so this plan doesn’t work as-is.

  5. skade commented on May 13, 2019

    @skade
    Contributor

    @SimonSapin Wasn't relating Any's bound discussed at some point?

  6. scottmcm commented on May 13, 2019

    @scottmcm
    Member

    On unstable we have #[marker] traits which cannot override anything in their impls -- if they were allowed to define associated items with defaults in their trait definition, it would be another way to do this, though that considered too large a change to make with just a PR in #53693 (comment).

  7. added a commit that references this issue on May 13, 2019
  8. cuviper commented on May 13, 2019

    @cuviper
    Member

    I'm not sure why this functionality should be left to the library at all. Maybe we really need a type_id_val paired to the existing intrinsics::type_id()? (Similar to size_of and size_of_val.)

  9. SimonSapin commented on May 13, 2019

    @SimonSapin
    Contributor

    @skade Yes, this was discussed to say that it would be unsound: #41875 (comment)


    @cuviper This sounds doable, but would require a TypeId value to be stored in every trait object vtable. This has some code size cost. The size and alignment of the underlying type (and pointer to drop_in_place<U>) are already special-cased like this, to allow Box<dyn Trait> to exist for any trait and be dropped/deallocated correctly. Having the type_id method be part of the Error trait puts (a way to get) the TypeId in vtables for dyn Error today.

    If we add fn type_id_of_val<T: ?Sized>(x: &T) -> TypeId we’d also need to carefully define its semantics. With foo: &dyn SomeTrait coerced from &U where U: SomeTrait, what’s interesting is here TypeId::of<T>(). But dyn SomeTrait is also a type, so TypeId::of<dyn SomeTrait>() also exists. If type_id_of_val(foo) returns the former, what should type_id_of_val(bar) return when T: Sized type? When T is a [X] slice?

    If rust-lang/rfcs#2580 is accepted and implemented we could have T: std::ptr::Pointee<Metadata = &'static VTable> to restrict a type parameter to dyn SomeTrait trait objects. Or more simply for this case, a type_id method on VTable (which in that RFC can be accessed through the std::ptr::metadata function.)

  10. 30 remaining items

  11. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    and removed
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    C-bugCategory: This is a bug.
    on May 20, 2019
  12. withoutboats commented on Jul 12, 2019

    @withoutboats
    Contributor

    I wouldn't want to stabilize this with the private type hack it currently uses, so I think a blocker on stabilizing this API is one of these two things:

    1. Making non-overrideable methods in traits.
    2. Making methods which are unsafe to implement (not to call) without making the entire trait unsafe to implement.
  13. programmerjake commented on Jul 12, 2019

    @programmerjake
    Member

    what about something like:

    pub unsafe trait ErrorTypeId {
        fn type_id(&self) -> TypeId where Self: 'static {
            TypeId::of::<Self>()
        }
    }
    
    unsafe impl<T: ?Sized> ErrorTypeId for T {}
    
    pub trait Error: Debug + Display + ErrorTypeId {
       // ...
    }
  14. leo60228 commented on Aug 2, 2019

    @leo60228
    Contributor

    @programmerjake I've slightly extended this by making it not specific to Error and wrote up an RFC. rust-lang/rfcs#2738

  15. programmerjake commented on Aug 4, 2019

    @programmerjake
    Member

    @programmerjake I've slightly extended this by making it not specific to Error and wrote up an RFC. rust-lang/rfcs#2738

    @leo60228 Thanks!

  16. added
    I-libs-radarLibs issues that are tracked on the team's radar.
    on Jul 30, 2020
  17. added
    PG-error-handlingProject group: Error handling (https://github.com/rust-lang/project-error-handling)
    on Sep 27, 2021
  18. lygstate commented on Jul 30, 2022

    @lygstate
    Contributor

    What's going on on this?

  19. programmerjake commented on Aug 20, 2024

    @programmerjake
    Member

    trait method impl restrictions rust-lang/rfcs#3678 would allow stabilizing this with a nice interface:

    pub impl(self) fn type_id(&self) -> TypeId {
        ...
    }
  20. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-error-handlingArea: Error handlingB-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCI-libs-radarLibs issues that are tracked on the team's radar.PG-error-handlingProject group: Error handling (https://github.com/rust-lang/project-error-handling)T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions