Skip to content

Commit 892cb14

Browse files
committed
Auto merge of #67290 - jonas-schievink:leak-audit, r=KodrAus
Audit liballoc for leaks in `Drop` impls when user destructor panics Inspired by #67243 and #67235, this audits and hopefully fixes the remaining `Drop` impls in liballoc for resource leaks in the presence of panics in destructors called by the affected `Drop` impl. This does not touch `Hash{Map,Set}` since they live in hashbrown. They have similar issues though. r? @KodrAus
2 parents 3a0d106 + e5987a0 commit 892cb14

File tree

11 files changed

+497
-128
lines changed

11 files changed

+497
-128
lines changed

src/liballoc/collections/binary_heap.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@
147147

148148
use core::fmt;
149149
use core::iter::{FromIterator, FusedIterator, TrustedLen};
150-
use core::mem::{size_of, swap, ManuallyDrop};
150+
use core::mem::{self, size_of, swap, ManuallyDrop};
151151
use core::ops::{Deref, DerefMut};
152152
use core::ptr;
153153

@@ -1239,7 +1239,19 @@ pub struct DrainSorted<'a, T: Ord> {
12391239
impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
12401240
/// Removes heap elements in heap order.
12411241
fn drop(&mut self) {
1242-
while let Some(_) = self.inner.pop() {}
1242+
struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>);
1243+
1244+
impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> {
1245+
fn drop(&mut self) {
1246+
while let Some(_) = self.0.inner.pop() {}
1247+
}
1248+
}
1249+
1250+
while let Some(item) = self.inner.pop() {
1251+
let guard = DropGuard(self);
1252+
drop(item);
1253+
mem::forget(guard);
1254+
}
12431255
}
12441256
}
12451257

src/liballoc/collections/btree/map.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,22 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
14701470
#[stable(feature = "btree_drop", since = "1.7.0")]
14711471
impl<K, V> Drop for IntoIter<K, V> {
14721472
fn drop(&mut self) {
1473-
self.for_each(drop);
1473+
struct DropGuard<'a, K, V>(&'a mut IntoIter<K, V>);
1474+
1475+
impl<'a, K, V> Drop for DropGuard<'a, K, V> {
1476+
fn drop(&mut self) {
1477+
// Continue the same loop we perform below. This only runs when unwinding, so we
1478+
// don't have to care about panics this time (they'll abort).
1479+
while let Some(_) = self.0.next() {}
1480+
}
1481+
}
1482+
1483+
while let Some(pair) = self.next() {
1484+
let guard = DropGuard(self);
1485+
drop(pair);
1486+
mem::forget(guard);
1487+
}
1488+
14741489
unsafe {
14751490
let leaf_node = ptr::read(&self.front).into_node();
14761491
if leaf_node.is_shared_root() {

src/liballoc/collections/linked_list.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,24 @@ where
16111611
F: FnMut(&mut T) -> bool,
16121612
{
16131613
fn drop(&mut self) {
1614-
self.for_each(drop);
1614+
struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>)
1615+
where
1616+
F: FnMut(&mut T) -> bool;
1617+
1618+
impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F>
1619+
where
1620+
F: FnMut(&mut T) -> bool,
1621+
{
1622+
fn drop(&mut self) {
1623+
self.0.for_each(drop);
1624+
}
1625+
}
1626+
1627+
while let Some(item) = self.next() {
1628+
let guard = DropGuard(self);
1629+
drop(item);
1630+
mem::forget(guard);
1631+
}
16151632
}
16161633
}
16171634

src/liballoc/collections/vec_deque.rs

+21-108
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ use crate::collections::TryReserveError;
2222
use crate::raw_vec::RawVec;
2323
use crate::vec::Vec;
2424

25+
#[stable(feature = "drain", since = "1.6.0")]
26+
pub use self::drain::Drain;
27+
28+
mod drain;
29+
2530
#[cfg(test)]
2631
mod tests;
2732

@@ -866,6 +871,18 @@ impl<T> VecDeque<T> {
866871
/// ```
867872
#[stable(feature = "deque_extras", since = "1.16.0")]
868873
pub fn truncate(&mut self, len: usize) {
874+
/// Runs the destructor for all items in the slice when it gets dropped (normally or
875+
/// during unwinding).
876+
struct Dropper<'a, T>(&'a mut [T]);
877+
878+
impl<'a, T> Drop for Dropper<'a, T> {
879+
fn drop(&mut self) {
880+
unsafe {
881+
ptr::drop_in_place(self.0);
882+
}
883+
}
884+
}
885+
869886
// Safe because:
870887
//
871888
// * Any slice passed to `drop_in_place` is valid; the second case has
@@ -888,8 +905,11 @@ impl<T> VecDeque<T> {
888905
let drop_back = back as *mut _;
889906
let drop_front = front.get_unchecked_mut(len..) as *mut _;
890907
self.head = self.wrap_sub(self.head, num_dropped);
908+
909+
// Make sure the second half is dropped even when a destructor
910+
// in the first one panics.
911+
let _back_dropper = Dropper(&mut *drop_back);
891912
ptr::drop_in_place(drop_front);
892-
ptr::drop_in_place(drop_back);
893913
}
894914
}
895915
}
@@ -2526,113 +2546,6 @@ impl<T> ExactSizeIterator for IntoIter<T> {
25262546
#[stable(feature = "fused", since = "1.26.0")]
25272547
impl<T> FusedIterator for IntoIter<T> {}
25282548

2529-
/// A draining iterator over the elements of a `VecDeque`.
2530-
///
2531-
/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its
2532-
/// documentation for more.
2533-
///
2534-
/// [`drain`]: struct.VecDeque.html#method.drain
2535-
/// [`VecDeque`]: struct.VecDeque.html
2536-
#[stable(feature = "drain", since = "1.6.0")]
2537-
pub struct Drain<'a, T: 'a> {
2538-
after_tail: usize,
2539-
after_head: usize,
2540-
iter: Iter<'a, T>,
2541-
deque: NonNull<VecDeque<T>>,
2542-
}
2543-
2544-
#[stable(feature = "collection_debug", since = "1.17.0")]
2545-
impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
2546-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2547-
f.debug_tuple("Drain")
2548-
.field(&self.after_tail)
2549-
.field(&self.after_head)
2550-
.field(&self.iter)
2551-
.finish()
2552-
}
2553-
}
2554-
2555-
#[stable(feature = "drain", since = "1.6.0")]
2556-
unsafe impl<T: Sync> Sync for Drain<'_, T> {}
2557-
#[stable(feature = "drain", since = "1.6.0")]
2558-
unsafe impl<T: Send> Send for Drain<'_, T> {}
2559-
2560-
#[stable(feature = "drain", since = "1.6.0")]
2561-
impl<T> Drop for Drain<'_, T> {
2562-
fn drop(&mut self) {
2563-
self.for_each(drop);
2564-
2565-
let source_deque = unsafe { self.deque.as_mut() };
2566-
2567-
// T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
2568-
//
2569-
// T t h H
2570-
// [. . . o o x x o o . . .]
2571-
//
2572-
let orig_tail = source_deque.tail;
2573-
let drain_tail = source_deque.head;
2574-
let drain_head = self.after_tail;
2575-
let orig_head = self.after_head;
2576-
2577-
let tail_len = count(orig_tail, drain_tail, source_deque.cap());
2578-
let head_len = count(drain_head, orig_head, source_deque.cap());
2579-
2580-
// Restore the original head value
2581-
source_deque.head = orig_head;
2582-
2583-
match (tail_len, head_len) {
2584-
(0, 0) => {
2585-
source_deque.head = 0;
2586-
source_deque.tail = 0;
2587-
}
2588-
(0, _) => {
2589-
source_deque.tail = drain_head;
2590-
}
2591-
(_, 0) => {
2592-
source_deque.head = drain_tail;
2593-
}
2594-
_ => unsafe {
2595-
if tail_len <= head_len {
2596-
source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
2597-
source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
2598-
} else {
2599-
source_deque.head = source_deque.wrap_add(drain_tail, head_len);
2600-
source_deque.wrap_copy(drain_tail, drain_head, head_len);
2601-
}
2602-
},
2603-
}
2604-
}
2605-
}
2606-
2607-
#[stable(feature = "drain", since = "1.6.0")]
2608-
impl<T> Iterator for Drain<'_, T> {
2609-
type Item = T;
2610-
2611-
#[inline]
2612-
fn next(&mut self) -> Option<T> {
2613-
self.iter.next().map(|elt| unsafe { ptr::read(elt) })
2614-
}
2615-
2616-
#[inline]
2617-
fn size_hint(&self) -> (usize, Option<usize>) {
2618-
self.iter.size_hint()
2619-
}
2620-
}
2621-
2622-
#[stable(feature = "drain", since = "1.6.0")]
2623-
impl<T> DoubleEndedIterator for Drain<'_, T> {
2624-
#[inline]
2625-
fn next_back(&mut self) -> Option<T> {
2626-
self.iter.next_back().map(|elt| unsafe { ptr::read(elt) })
2627-
}
2628-
}
2629-
2630-
#[stable(feature = "drain", since = "1.6.0")]
2631-
impl<T> ExactSizeIterator for Drain<'_, T> {}
2632-
2633-
#[stable(feature = "fused", since = "1.26.0")]
2634-
impl<T> FusedIterator for Drain<'_, T> {}
2635-
26362549
#[stable(feature = "rust1", since = "1.0.0")]
26372550
impl<A: PartialEq> PartialEq for VecDeque<A> {
26382551
fn eq(&self, other: &VecDeque<A>) -> bool {
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use core::iter::FusedIterator;
2+
use core::ptr::{self, NonNull};
3+
use core::{fmt, mem};
4+
5+
use super::{count, Iter, VecDeque};
6+
7+
/// A draining iterator over the elements of a `VecDeque`.
8+
///
9+
/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its
10+
/// documentation for more.
11+
///
12+
/// [`drain`]: struct.VecDeque.html#method.drain
13+
/// [`VecDeque`]: struct.VecDeque.html
14+
#[stable(feature = "drain", since = "1.6.0")]
15+
pub struct Drain<'a, T: 'a> {
16+
pub(crate) after_tail: usize,
17+
pub(crate) after_head: usize,
18+
pub(crate) iter: Iter<'a, T>,
19+
pub(crate) deque: NonNull<VecDeque<T>>,
20+
}
21+
22+
#[stable(feature = "collection_debug", since = "1.17.0")]
23+
impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
24+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25+
f.debug_tuple("Drain")
26+
.field(&self.after_tail)
27+
.field(&self.after_head)
28+
.field(&self.iter)
29+
.finish()
30+
}
31+
}
32+
33+
#[stable(feature = "drain", since = "1.6.0")]
34+
unsafe impl<T: Sync> Sync for Drain<'_, T> {}
35+
#[stable(feature = "drain", since = "1.6.0")]
36+
unsafe impl<T: Send> Send for Drain<'_, T> {}
37+
38+
#[stable(feature = "drain", since = "1.6.0")]
39+
impl<T> Drop for Drain<'_, T> {
40+
fn drop(&mut self) {
41+
struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>);
42+
43+
impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> {
44+
fn drop(&mut self) {
45+
self.0.for_each(drop);
46+
47+
let source_deque = unsafe { self.0.deque.as_mut() };
48+
49+
// T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
50+
//
51+
// T t h H
52+
// [. . . o o x x o o . . .]
53+
//
54+
let orig_tail = source_deque.tail;
55+
let drain_tail = source_deque.head;
56+
let drain_head = self.0.after_tail;
57+
let orig_head = self.0.after_head;
58+
59+
let tail_len = count(orig_tail, drain_tail, source_deque.cap());
60+
let head_len = count(drain_head, orig_head, source_deque.cap());
61+
62+
// Restore the original head value
63+
source_deque.head = orig_head;
64+
65+
match (tail_len, head_len) {
66+
(0, 0) => {
67+
source_deque.head = 0;
68+
source_deque.tail = 0;
69+
}
70+
(0, _) => {
71+
source_deque.tail = drain_head;
72+
}
73+
(_, 0) => {
74+
source_deque.head = drain_tail;
75+
}
76+
_ => unsafe {
77+
if tail_len <= head_len {
78+
source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
79+
source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
80+
} else {
81+
source_deque.head = source_deque.wrap_add(drain_tail, head_len);
82+
source_deque.wrap_copy(drain_tail, drain_head, head_len);
83+
}
84+
},
85+
}
86+
}
87+
}
88+
89+
while let Some(item) = self.next() {
90+
let guard = DropGuard(self);
91+
drop(item);
92+
mem::forget(guard);
93+
}
94+
95+
DropGuard(self);
96+
}
97+
}
98+
99+
#[stable(feature = "drain", since = "1.6.0")]
100+
impl<T> Iterator for Drain<'_, T> {
101+
type Item = T;
102+
103+
#[inline]
104+
fn next(&mut self) -> Option<T> {
105+
self.iter.next().map(|elt| unsafe { ptr::read(elt) })
106+
}
107+
108+
#[inline]
109+
fn size_hint(&self) -> (usize, Option<usize>) {
110+
self.iter.size_hint()
111+
}
112+
}
113+
114+
#[stable(feature = "drain", since = "1.6.0")]
115+
impl<T> DoubleEndedIterator for Drain<'_, T> {
116+
#[inline]
117+
fn next_back(&mut self) -> Option<T> {
118+
self.iter.next_back().map(|elt| unsafe { ptr::read(elt) })
119+
}
120+
}
121+
122+
#[stable(feature = "drain", since = "1.6.0")]
123+
impl<T> ExactSizeIterator for Drain<'_, T> {}
124+
125+
#[stable(feature = "fused", since = "1.26.0")]
126+
impl<T> FusedIterator for Drain<'_, T> {}

0 commit comments

Comments
 (0)