Skip to content

Assignments leave their place partially-destroyed if the destructor panics #30380

Closed
@arielb1

Description

@arielb1

STR

struct Bomb;
struct Observer<'a>(&'a mut (String, Bomb));

impl Drop for Bomb {
    fn drop(&mut self) {
        panic!("panicking destructors ftw!");
    }
}

impl<'a> Drop for Observer<'a> {
    fn drop(&mut self) {
        let _spray = "0wned".to_owned();
        println!("{}", &self.0 .0);
    }
}

fn foo(b: &mut Observer) {
    *b.0 = ("~".to_owned(), Bomb);
}

fn main() {
    let mut bomb = ("clear".to_owned(), Bomb);
    let mut observer = Observer(&mut bomb);
    foo(&mut observer);
}

Results

The assignment to *b.0 within foo calls the drop-glue for the value inside. The new tuple ("~", Bomb) is created, and then the drop glue for the old value of b is executed. It first frees the original string, and then attempts to calls Bomb's destructor. As the latter destructor panics, the function unwinds without storing a value in the place of the missing String, leaving a &mut reference that points to an invalid value, which can later be observed by a destructor or recover.

Fixes

The new value for the destination is available the whole time - the panic handler can just write it in.

Metadata

Metadata

Assignees

Labels

A-destructorsArea: Destructors (`Drop`, …)I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-mediumMedium 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