Skip to content

Evade borrowck by wrapping your lifetime crimes in a simple closure #112056

Closed
@cormac-ainc

Description

@cormac-ainc

The following code compiles, since February nightlies and on stable version 1.69 (no older stable versions are affected). (playground):

struct Spooky<'b> {
    owned: String,
    borrowed: &'b str,
}

impl<'b> Spooky<'b> {
    fn create_self_reference<'a>(&'a mut self) {
        let mut closure = || {
            let borrow: &'a String = &self.owned;
            self.borrowed = borrow;
        };
        closure();
    }
}

fn main() {
    let mut spooky: Spooky<'static> = Spooky {
        owned: "Hello".to_string(),
        borrowed: "static string, initially",
    };
    spooky.create_self_reference();
    std::mem::take(&mut spooky.owned);
    for _ in 0..1000 {
        let _ = format!("askld");
    }
    println!("{}", spooky.borrowed);
}

This is clearly a use-after-free. On my Linux machine it prints a garbage string. It should not compile at all, the error should be basically the same as if you didn't wrap the offending lines in a closure. The issue still occurs with self.borrowed = &self.owned, the annotations are just for clarity.

The problem was introduced in #107969.

Hat tip to @ladecaz for writing the cursed code that got us here.

cargo-bisect-rustc results

searched nightlies: from nightly-2021-04-25 to nightly-2023-05-29
regressed nightly: nightly-2023-02-21
searched commit range: 7aa413d...5243ea5
regressed commit: e7eaed2

bisected with cargo-bisect-rustc v0.6.6

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc --start=2021-04-25 --regress success

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-criticalCritical priorityT-typesRelevant to the types 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