Skip to content

Commit 48164f8

Browse files
authored
Rollup merge of #67235 - jonas-schievink:vecdeque-leak, r=KodrAus
VecDeque: drop remaining items on destructor panic Closes #67232
2 parents df9e491 + 82c09b7 commit 48164f8

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

src/liballoc/collections/vec_deque.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,23 @@ impl<T: Clone> Clone for VecDeque<T> {
144144
#[stable(feature = "rust1", since = "1.0.0")]
145145
unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
146146
fn drop(&mut self) {
147+
/// Runs the destructor for all items in the slice when it gets dropped (normally or
148+
/// during unwinding).
149+
struct Dropper<'a, T>(&'a mut [T]);
150+
151+
impl<'a, T> Drop for Dropper<'a, T> {
152+
fn drop(&mut self) {
153+
unsafe {
154+
ptr::drop_in_place(self.0);
155+
}
156+
}
157+
}
158+
147159
let (front, back) = self.as_mut_slices();
148160
unsafe {
161+
let _back_dropper = Dropper(back);
149162
// use drop for [T]
150163
ptr::drop_in_place(front);
151-
ptr::drop_in_place(back);
152164
}
153165
// RawVec handles deallocation
154166
}

src/liballoc/tests/vec_deque.rs

+34
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::TryReserveError::*;
22
use std::collections::{vec_deque::Drain, VecDeque};
33
use std::fmt::Debug;
44
use std::mem::size_of;
5+
use std::panic::catch_unwind;
56
use std::{isize, usize};
67

78
use crate::hash;
@@ -709,6 +710,39 @@ fn test_drop_clear() {
709710
assert_eq!(unsafe { DROPS }, 4);
710711
}
711712

713+
#[test]
714+
fn test_drop_panic() {
715+
static mut DROPS: i32 = 0;
716+
717+
struct D(bool);
718+
719+
impl Drop for D {
720+
fn drop(&mut self) {
721+
unsafe {
722+
DROPS += 1;
723+
}
724+
725+
if self.0 {
726+
panic!("panic in `drop`");
727+
}
728+
}
729+
}
730+
731+
let mut q = VecDeque::new();
732+
q.push_back(D(false));
733+
q.push_back(D(false));
734+
q.push_back(D(false));
735+
q.push_back(D(false));
736+
q.push_back(D(false));
737+
q.push_front(D(false));
738+
q.push_front(D(false));
739+
q.push_front(D(true));
740+
741+
catch_unwind(move || drop(q)).ok();
742+
743+
assert_eq!(unsafe { DROPS }, 8);
744+
}
745+
712746
#[test]
713747
fn test_reserve_grow() {
714748
// test growth path A

0 commit comments

Comments
 (0)