diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-03-31 00:26:32 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-31 00:26:32 +0200 |
| commit | d6c959c680df8e3a68932e42ed919f5664669cc7 (patch) | |
| tree | 367e984f66e6d0b2253cb0a546a9f2b0a757e2c9 /library/alloc/src | |
| parent | 86388f617178875af0b6a585479efa4f09abd630 (diff) | |
| parent | d9a438dc73de6ff146ae3e6bc4050b7cea41b09e (diff) | |
| download | rust-d6c959c680df8e3a68932e42ed919f5664669cc7.tar.gz rust-d6c959c680df8e3a68932e42ed919f5664669cc7.zip | |
Rollup merge of #95298 - jhorstmann:fix-double-drop-of-allocator-in-vec-into-iter, r=oli-obk
Fix double drop of allocator in IntoIter impl of Vec Fixes #95269 The `drop` impl of `IntoIter` reconstructs a `RawVec` from `buf`, `cap` and `alloc`, when that `RawVec` is dropped it also drops the allocator. To avoid dropping the allocator twice we wrap it in `ManuallyDrop` in the `InttoIter` struct. Note this is my first contribution to the standard library, so I might be missing some details or a better way to solve this.
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/vec/into_iter.rs | 15 | ||||
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 2 |
2 files changed, 10 insertions, 7 deletions
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index cc6dfb0e330..03c532bb697 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -8,7 +8,8 @@ use core::iter::{ FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, }; use core::marker::PhantomData; -use core::mem::{self}; +use core::mem::{self, ManuallyDrop}; +use core::ops::Deref; use core::ptr::{self, NonNull}; use core::slice::{self}; @@ -32,7 +33,9 @@ pub struct IntoIter< pub(super) buf: NonNull<T>, pub(super) phantom: PhantomData<T>, pub(super) cap: usize, - pub(super) alloc: A, + // the drop impl reconstructs a RawVec from buf, cap and alloc + // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop + pub(super) alloc: ManuallyDrop<A>, pub(super) ptr: *const T, pub(super) end: *const T, } @@ -295,11 +298,11 @@ where impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> { #[cfg(not(test))] fn clone(&self) -> Self { - self.as_slice().to_vec_in(self.alloc.clone()).into_iter() + self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter() } #[cfg(test)] fn clone(&self) -> Self { - crate::slice::to_vec(self.as_slice(), self.alloc.clone()).into_iter() + crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter() } } @@ -311,8 +314,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> { impl<T, A: Allocator> Drop for DropGuard<'_, T, A> { fn drop(&mut self) { unsafe { - // `IntoIter::alloc` is not used anymore after this - let alloc = ptr::read(&self.0.alloc); + // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec + let alloc = ManuallyDrop::take(&mut self.0.alloc); // RawVec handles deallocation let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1ca5ee55375..9773ec02337 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2579,7 +2579,7 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> { fn into_iter(self) -> IntoIter<T, A> { unsafe { let mut me = ManuallyDrop::new(self); - let alloc = ptr::read(me.allocator()); + let alloc = ManuallyDrop::new(ptr::read(me.allocator())); let begin = me.as_mut_ptr(); let end = if mem::size_of::<T>() == 0 { arith_offset(begin as *const i8, me.len() as isize) as *const T |
