Skip to content

Double free in Vec::from_iter specialization when drop panics #83618

Closed
@Qwaz

Description

@Qwaz

// drop any remaining values at the tail of the source
src.drop_remaining();

pub(super) fn drop_remaining(&mut self) {
unsafe {
ptr::drop_in_place(self.as_mut_slice());
}
self.ptr = self.end;
}

SpecFromIter<T, I> for Vec<T> calls Vec::IntoIter::drop_remaining(). drop_remaining() calls drop_in_place() before overwriting the pointer. As a result, dropped elements are not invalidated and dropped again under panic.

PoC:

#![forbid(unsafe_code)]

use std::iter::FromIterator;

#[derive(Debug)]
enum MyEnum {
    DroppedTwice(Box<i32>),
    PanicOnDrop,
}

impl Drop for MyEnum {
    fn drop(&mut self) {
        match self {
            MyEnum::DroppedTwice(_) => println!("Dropping!"),
            MyEnum::PanicOnDrop => {
                if !std::thread::panicking() {
                    panic!();
                }
            }
        }
    }
}

fn main() {
    let v = vec![MyEnum::DroppedTwice(Box::new(123)), MyEnum::PanicOnDrop];
    Vec::from_iter(v.into_iter().take(0));
}

Output:

Dropping!
thread 'main' panicked at 'explicit panic', src/main.rs:17:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Dropping!
free(): double free detected in tcache 2

Tested with rustc 1.51.0. Here is a playground link to the code snippet.

Metadata

Metadata

Assignees

Labels

A-collectionsArea: `std::collections`A-destructorsArea: Destructors (`Drop`, …)C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-criticalCritical priorityT-libsRelevant to the library 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