Skip to content

object-safe traits can have associated types with unchecked bounds #27675

Closed

Description

@arielb1

STR

trait Foo { type Assoc: PartialEq<Box<Self>>; }
impl Foo for u32 { type Assoc = Box<u32>; }

fn foo<T: Foo+?Sized>(u: Box<T>, v: T::Assoc) -> bool {
    &v == &u
}

fn main() {
    let bar: Box<Foo<Assoc=Box<u32>>> = Box::new(4);
    foo(bar, Box::new(5));
}

Result

<anon>:5:5: 5:13 error: internal compiler error: Encountered errors `[FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<Box<u32> as core::cmp::PartialEq<Box<Foo<Assoc=Box<u32>> + 'static>>>)),depth=1),Unimplemented)]` fulfilling during trans

I guess this should be banned.

cc @nikomatsakis

Activity

  1. arielb1 commented on Aug 11, 2015

    @arielb1
    ContributorAuthor

    Related:

    use std::fmt;
    
    trait Foo {
        type Assoc: 'static;
    }
    
    fn foo<T: Foo+?Sized>(t: T::Assoc) -> Box<fmt::Display+'static>
            where T::Assoc: fmt::Display {
        Box::new(t)
    }
    
    fn wat() -> Box<fmt::Display+'static> {
        let x = 42;
        foo::<Foo<Assoc=&u32>>(&x)
    }
    
    fn main() {
        println!("{}", wat());
    }
  2. nikomatsakis commented on Aug 11, 2015

    @nikomatsakis
    Contributor

    Interesting. I agree that it should be illegal and we should amend WF relations for object types to check that the bindings cover the requirements of the trait -- the RFC was incomplete on this topic.

  3. pnkfelix commented on Jan 21, 2016

    @pnkfelix
    Contributor

    The example from the first comment (#27675 (comment)) is actually scarier than the original bug description; at least, I usually can think "oh, an ICE, well that might just be something that won't actually ever compile"; but the first comment is showing code that is indeed a case of "wat"!

  4. added
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    on Jan 21, 2016
  5. changed the title [-]object-safe traits can have associated types with Self-containing bounds[/-] [+]object-safe traits can have associated types with unchecked bounds[/+] on Jan 21, 2016
  6. pnkfelix commented on Jul 7, 2016

    @pnkfelix
    Contributor

    triage: P-medium

  7. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Sep 15, 2019
  8. added
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Jun 9, 2020
  9. removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Jun 9, 2020
  10. 197g commented on Sep 22, 2020

    @197g
    Contributor

    Since this has not been demonstrated: We can indeed build a safe, arbitrary transmutation primitive from this, though this will ICE in practice except if used only for the purpose of the second comment, casting away lifetimes.

    trait Id<T>: Sized {
        fn id(self) -> T;
    }
    impl<T> Id<T> for T {
        fn id(self) -> T { self }
    }
    
    trait Setup<T> {
        type From: Id<T>;
    }
    
    fn transmute<T, U: Setup<T> + ?Sized>(from: U::From) -> T {
        Id::id(from)
    }
    
    // compiles fine
    pub fn safe_transmute<T, U>(t: T) -> U {
        transmute::<U, dyn Setup<U, From=T>>(t)
    }
    fn main() {
        let static_word = {
            let st = String::from("Hello!");
            safe_transmute::<_, &'static mut str>(&*st)
        };
        
        println!("{:?}", static_word);
    }
    // ICE
    fn main() {
        safe_transmute::<usize, &'static str>(0usize);
    }
  11. 197g commented on Sep 22, 2020

    @197g
    Contributor

    Uuups, we can make any type Copy. That's quite severe, wouldn't you say?

    trait Setup {
        type From: Copy;
    }
    
    fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
        *from
    }
    
    pub fn copy_any<T>(t: &T) -> T {
        copy::<dyn Setup<From=T>>(t)
    }
    
    fn main() {
        let st = String::from("Hello");
        copy_any(&st);
    }
  12. 7 remaining items

  13. added
    I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
    on Sep 22, 2020
  14. camelid commented on Sep 22, 2020

    @camelid
    Member

    Decided on P-high as discussed in the prioritization working group procedure.

  15. 197g commented on Sep 22, 2020

    @197g
    Contributor

    For completeness sake. This may be used to send any reference across threads:

    trait Id<T> {
        fn id(&self) -> &T;
    }
    
    impl<T> Id<T> for T {
        fn id(&self) -> &T { self }
    }
    
    trait SyncSetup<T> {
        type From: Id<T> + Sync + 'static;
    }
    
    fn cast<T, U>(from: &T) -> &(dyn Id<U> + Sync) {
        fn do_it<T, U: ?Sized + SyncSetup<T>>(val: &U::From) -> &(dyn Id<T> + Sync) {
            val
        }
        
        do_it::<U, dyn SyncSetup<U, From=T>>(from)
    }
    
    fn syncify<T>(from: &T) -> &'static (dyn Id<T> + Sync) {
        // Very carefully avoid ICE. This only adds marker trait to an unsized trait.
        let x: &(dyn Id<T> + Sync) = cast(from);
        // Indirect over another reference and make `x` appear `&'static`.
        // Lifetime change is invisible to trait materialization checks.
        let y: &(dyn Id<&'static (dyn Id<T> + Sync)>) = cast(&x);
        // .. and grab that one.
        let x: &'static (dyn Id<T> + Sync) = *(y.id());
        x
    }
    
    use std::cell::Cell;
    fn main() {
        let st = Cell::new(0u32);
        let x = syncify(&st);
        
        std::thread::spawn(move || {
            x.id().set(1);
        });
        
        while st.get() == 0 {}
        println!("Spooky");
    }
  16. Aaron1011 commented on Sep 23, 2020

    @Aaron1011
    Contributor

    I suspect that this will be fixed by #73905

  17. lqd commented on Sep 24, 2020

    @lqd
    Member

    The 4 weaponized examples above will indeed be rejected with #73905

  18. added a commit that references this issue on Oct 8, 2020
  19. Aaron1011 commented on Oct 9, 2020

    @Aaron1011
    Contributor

    A regression test was added in #77663.

  20. added a commit that references this issue on Nov 24, 2020
  21. added a commit that references this issue on Jan 1, 2021
  22. added a commit that references this issue on May 11, 2026
  23. added a commit that references this issue on May 14, 2026
  24. added a commit that references this issue on Oct 17, 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-trait-systemArea: Trait systemA-type-systemArea: Type systemC-bugCategory: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-highHigh priorityT-compilerRelevant to the compiler 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