Skip to content

Commit

Permalink
fix double-drop in in-place collect specialization
Browse files Browse the repository at this point in the history
(cherry picked from commit 421f5d2)
  • Loading branch information
the8472 authored and cuviper committed Apr 26, 2021
1 parent 6ed66eb commit 836fef0
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 11 deletions.
27 changes: 18 additions & 9 deletions library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,29 @@ impl<T, A: Allocator> IntoIter<T, A> {
ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
}

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

/// Relinquishes the backing allocation, equivalent to
/// `ptr::write(&mut self, Vec::new().into_iter())`
pub(super) fn forget_allocation(&mut self) {
// overwrite the individual fields instead of creating a new
// struct and then overwriting &mut self.
// this creates less assembly
self.cap = 0;
self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) };
self.ptr = self.buf.as_ptr();
self.end = self.buf.as_ptr();

unsafe {
ptr::drop_in_place(remaining);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/vec/source_iter_marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ where
}

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

let vec = unsafe {
let len = dst.offset_from(dst_buf) as usize;
Expand Down

0 comments on commit 836fef0

Please sign in to comment.