Skip to content

Reborrow unsoundness due to not checking for Copy #156380

Closed

Description

@theemathas

This unsoundness was discovered by @coolcatcoder. I'm filing this issue on their behalf.

The following code causes a double free. It should not compile.

#![feature(reborrow)]

#[expect(dead_code)]
// This code correctly gives a compile error if &'a mut () is changed to &'a ()
struct Wrap<'a>(&'a mut (), String);

impl<'a> std::marker::Reborrow for Wrap<'a> {}

fn get(x: Wrap<'_>) -> String {
    x.1
}

fn main() {
    let x = Wrap(&mut (), String::from("a"));
    let _y = get(x);
    let _z = get(x);
}

cc @aapoalas

Meta

Reproducible on the playground with version 1.97.0-nightly (2026-05-08 fb0a5a5a9c892b351f34)

Activity

  1. added
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    C-bugCategory: This is a bug.
    T-typesRelevant to the types team, which will review and decide on the PR/issue.
    F-reborrow`#![feature(reborrow)]`; see #145612
    on May 10, 2026
  2. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on May 10, 2026
  3. removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on May 10, 2026
  4. theemathas commented on May 10, 2026

    @theemathas
    ContributorAuthor

    Below is a related unsoundness which I independently discovered. This code creates aliasing &muts, which should not be allowed.

    #![feature(reborrow)]
    
    #[expect(dead_code)]
    // This works even if the field is &'a (), not &'a mut ()
    struct Wrap<'a, T>(&'a (), T);
    impl<'a> std::marker::Reborrow for Wrap<'a, &'static mut i32> {}
    
    fn get<'a, 'b>(x: Wrap<'a, &'b mut i32>) -> &'b mut i32 {
        x.1
    }
    
    fn main() {
        let mut x = 1;
        let thing = Wrap(&(), &mut x);
        let y = get(thing);
        let z = get(thing);
        *y = 2;
        *z = 3;
        *y = 4;
        *z = 5;
        assert!(std::ptr::eq(y, z));
    }
  5. theemathas commented on May 24, 2026

    @theemathas
    ContributorAuthor

    The first snippet in this issue has been fixed by #156784. The second snippet has not been fixed yet.

  6. Jules-Bertholet commented on Sep 30, 2026

    @Jules-Bertholet
    Contributor

    The second snipped no longer compiles

  7. added
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Sep 30, 2026
  8. added
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    on Oct 13, 2026
  9. yashaggarwal85d commented on Oct 25, 2026

    @yashaggarwal85d
  10. added 2 commits that reference this issue on Oct 26, 2026
  11. added a commit that references this issue on Oct 26, 2026
  12. added a commit that references this issue on Oct 26, 2026
  13. added a commit that references this issue on Oct 26, 2026
  14. added a commit that references this issue on Oct 26, 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

    C-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.F-reborrow`#![feature(reborrow)]`; see #145612I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-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