Fix VecDeque::truncate
leak on drop panic
This commit is contained in:
parent
a859ca5c87
commit
3e5eb2634c
2 changed files with 50 additions and 2 deletions
|
@ -866,6 +866,18 @@ impl<T> VecDeque<T> {
|
|||
/// ```
|
||||
#[stable(feature = "deque_extras", since = "1.16.0")]
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
/// Runs the destructor for all items in the slice when it gets dropped (normally or
|
||||
/// during unwinding).
|
||||
struct Dropper<'a, T>(&'a mut [T]);
|
||||
|
||||
impl<'a, T> Drop for Dropper<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Safe because:
|
||||
//
|
||||
// * Any slice passed to `drop_in_place` is valid; the second case has
|
||||
|
@ -888,8 +900,11 @@ impl<T> VecDeque<T> {
|
|||
let drop_back = back as *mut _;
|
||||
let drop_front = front.get_unchecked_mut(len..) as *mut _;
|
||||
self.head = self.wrap_sub(self.head, num_dropped);
|
||||
|
||||
// Make sure the second half is dropped even when a destructor
|
||||
// in the first one panics.
|
||||
let _back_dropper = Dropper(&mut *drop_back);
|
||||
ptr::drop_in_place(drop_front);
|
||||
ptr::drop_in_place(drop_back);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::TryReserveError::*;
|
|||
use std::collections::{vec_deque::Drain, VecDeque};
|
||||
use std::fmt::Debug;
|
||||
use std::mem::size_of;
|
||||
use std::panic::catch_unwind;
|
||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
use std::{isize, usize};
|
||||
|
||||
use crate::hash;
|
||||
|
@ -1573,3 +1573,36 @@ fn test_try_rfold_moves_iter() {
|
|||
assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None);
|
||||
assert_eq!(iter.next_back(), Some(&70));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn truncate_leak() {
|
||||
static mut DROPS: i32 = 0;
|
||||
|
||||
struct D(bool);
|
||||
|
||||
impl Drop for D {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROPS += 1;
|
||||
}
|
||||
|
||||
if self.0 {
|
||||
panic!("panic in `drop`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut q = VecDeque::new();
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_front(D(true));
|
||||
q.push_front(D(false));
|
||||
q.push_front(D(false));
|
||||
|
||||
catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok();
|
||||
|
||||
assert_eq!(unsafe { DROPS }, 7);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue