Skip to content

Borrowck allows two mutable borrows when using match ergonomics #51117

Closed
@Arnavion

Description

@Arnavion

... which can be used to trigger a UAF in safe code.

rustc 1.26.0 (a77568041 2018-05-07)
binary: rustc
commit-hash: a7756804103447ea4e68a71ccf071e7ad8f7a03e
commit-date: 2018-05-07
host: x86_64-pc-windows-msvc
release: 1.26.0
LLVM version: 6.0
fn main() {
    let mut foo = Some("foo".to_string());
    let bar = &mut foo;
    match bar {
        Some(baz) => {
            bar.take();
            println!("{:?}", baz); // UAF, segfaults or prints garbage
        },
        None => unreachable!(),
    }
}

Original repro:

enum CacheFuture {
    Get(Option<String>)
}

fn main() {
    let mut f = CacheFuture::Get(Some("foo".to_string()));
    match &mut f {
        CacheFuture::Get(get) => match get {
            Some(mod_name) => {
                get.take();
                println!("{:?}", mod_name); // UAF, segfaults or prints garbage
            },
            None => unreachable!(),
        },
    }
}

Inserting explicit annotations to disable match ergonomics leads to borrowck correctly complaining about two mutable borrows, which leads me to believe this is only because of match ergonomics.

enum CacheFuture {
    Get(Option<String>)
}

fn main() {
    let mut f = CacheFuture::Get(Some("foo".to_string()));
    match *(&mut f) {
        CacheFuture::Get(ref mut get) => match *get {
            Some(ref mut mod_name) => {
                get.take();
                println!("{:?}", mod_name);
            },
            None => unreachable!(),
        },
    }
}
9  |             Some(ref mut mod_name) => {
   |                  ---------------- first mutable borrow occurs here
10 |                 get.take();
   |                 ^^^ second mutable borrow occurs here
...
14 |         },
   |         - first borrow ends here

Metadata

Metadata

Assignees

Labels

A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions