Skip to content

Unsoundness in Polonius involving impl Trait #161038

Open

Description

@theemathas

The following code was created based on #160979 with trial and error. It compiles in nightly and segfaults. It doesn't compile with -Zpolonius=off.

type Payload = Box<i32>;

trait Produce<'a> {
    fn produce(self) -> &'a &'a Payload;
}
impl<'a> Produce<'a> for &'a &'a Payload {
    fn produce(self) -> &'a &'a Payload {
        self
    }
}

trait Outlives<'a, 'b> {
    fn shorten(x: impl Produce<'a> + 'a) -> impl Produce<'a> + 'b;
}
impl<'a: 'b, 'b> Outlives<'a, 'b> for () {
    fn shorten(x: impl Produce<'a> + 'a) -> impl Produce<'a> + 'b {
        x
    }
}

fn make_producer<'a, 'b>(payload: &'a &'b Payload) -> impl Produce<'a> + 'b + use<'a, 'b>
where
    (): Outlives<'a, 'b>,
{
    <()>::shorten(payload)
}

fn main() {
    let wrong: &&Payload;
    let a = Box::new(1);
    {
        let mut r: &Payload = &a;
        let x: &&Payload = &r;
        wrong = make_producer(x).produce();
        r = &*Box::new(Box::new(2));
    }
    println!("{wrong}");
}

Meta

Reproducible on the playground with version 1.99.0-nightly (2026-08-12 c98d0cb27cc63afdd626)

Activity

  1. added
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.
    C-bugCategory: This is a bug.
    NLL-poloniusIssues related for using Polonius in the borrow checker
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    T-typesRelevant to the types team, which will review and decide on the PR/issue.
    A-implied-boundsArea: Implied bounds / inferred outlives-bounds
    on Aug 13, 2026
  2. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 13, 2026
  3. removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 13, 2026
  4. theemathas commented on Aug 13, 2026

    @theemathas
    ContributorAuthor

    Simplified a bit:

    type Payload = Box<i32>;
    
    trait Produce<'a> {
        fn produce(self) -> &'a Payload;
    }
    impl<'a> Produce<'a> for &'a Payload {
        fn produce(self) -> &'a Payload {
            self
        }
    }
    
    trait Outlives<'a, 'b> {
        fn shorten(x: impl Produce<'a> + 'a) -> impl Produce<'a> + 'b;
    }
    impl<'a: 'b, 'b> Outlives<'a, 'b> for () {
        fn shorten(x: impl Produce<'a> + 'a) -> impl Produce<'a> + 'b {
            x
        }
    }
    
    fn make_producer<'a, 'b>(payload: &'a Payload) -> impl Produce<'a> + 'b + use<'a, 'b>
    where
        (): Outlives<'a, 'b>,
    {
        <()>::shorten(payload)
    }
    
    fn main() {
        let wrong: &Payload;
        {
            let x: Box<Payload> = Box::new(Box::new(1));
            let r: &Payload = &*x;
            wrong = make_producer(r).produce();
        }
        println!("{wrong}");
    }
  5. theemathas commented on Aug 13, 2026

    @theemathas
    ContributorAuthor

    Surprisingly, annotating the type in the above code as let wrong: &'static Payload still results in code that compiles. Despite this, using a turbofish like make_producer::<'static, '_> or make_producer::<'_, 'static> results in a compile error.

  6. theemathas commented on Aug 21, 2026

    @theemathas
    ContributorAuthor

    There are a few more ways to cause unsoundness found at #t-types/polonius > Reporting a few Polonius bugs @ 💬 (listed as "bug 2" through "bug 7"), which might or might not have the same root cause.

  7. added 3 commits that reference this issue on Oct 27, 2026
  8. added a commit that references this issue on Oct 27, 2026
  9. added a commit that references this issue on Oct 27, 2026
  10. added
    S-bug-has-testStatus: This bug is tracked inside the repo by a `known-bug` test.
    on Oct 28, 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-borrow-checkerArea: The borrow checkerA-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessNLL-poloniusIssues related for using Polonius in the borrow checkerS-bug-has-testStatus: This bug is tracked inside the repo by a `known-bug` test.T-typesRelevant to the types team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions