Skip to content

Commit 421f5d2

Browse files
committed
fix double-drop in in-place collect specialization
1 parent fa89c0f commit 421f5d2

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

library/alloc/src/vec/into_iter.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,29 @@ impl<T, A: Allocator> IntoIter<T, A> {
8585
ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
8686
}
8787

88-
pub(super) fn drop_remaining(&mut self) {
89-
unsafe {
90-
ptr::drop_in_place(self.as_mut_slice());
91-
}
92-
self.ptr = self.end;
93-
}
88+
/// Drops remaining elements and relinquishes the backing allocation.
89+
///
90+
/// This is roughly equivalent to the following, but more efficient
91+
///
92+
/// ```
93+
/// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter();
94+
/// (&mut into_iter).for_each(core::mem::drop);
95+
/// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); }
96+
/// ```
97+
pub(super) fn forget_allocation_drop_remaining(&mut self) {
98+
let remaining = self.as_raw_mut_slice();
9499

95-
/// Relinquishes the backing allocation, equivalent to
96-
/// `ptr::write(&mut self, Vec::new().into_iter())`
97-
pub(super) fn forget_allocation(&mut self) {
100+
// overwrite the individual fields instead of creating a new
101+
// struct and then overwriting &mut self.
102+
// this creates less assembly
98103
self.cap = 0;
99104
self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
100105
self.ptr = self.buf.as_ptr();
101106
self.end = self.buf.as_ptr();
107+
108+
unsafe {
109+
ptr::drop_in_place(remaining);
110+
}
102111
}
103112
}
104113

library/alloc/src/vec/source_iter_marker.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ where
6969
}
7070

7171
// drop any remaining values at the tail of the source
72-
src.drop_remaining();
7372
// but prevent drop of the allocation itself once IntoIter goes out of scope
74-
src.forget_allocation();
73+
// if the drop panics then we also leak any elements collected into dst_buf
74+
src.forget_allocation_drop_remaining();
7575

7676
let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };
7777

0 commit comments

Comments
 (0)