diff options
| author | Giacomo Stevanato <giaco.stevanato@gmail.com> | 2022-09-10 11:26:24 +0200 |
|---|---|---|
| committer | Giacomo Stevanato <giaco.stevanato@gmail.com> | 2022-09-10 11:34:22 +0200 |
| commit | fa61678a7d471cfc8bf166979674d4574a5d3bec (patch) | |
| tree | 547dec33259cee732b5c40e6b5948c1d192e6d44 /library/alloc/src/vec | |
| parent | 36e530cb08950f1d03ab733e43ecec2802d099cf (diff) | |
| download | rust-fa61678a7d471cfc8bf166979674d4574a5d3bec.tar.gz rust-fa61678a7d471cfc8bf166979674d4574a5d3bec.zip | |
Fix leaking in inplace collection when destructor panics
Diffstat (limited to 'library/alloc/src/vec')
| -rw-r--r-- | library/alloc/src/vec/in_place_collect.rs | 8 | ||||
| -rw-r--r-- | library/alloc/src/vec/in_place_drop.rs | 15 | ||||
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 2 |
3 files changed, 22 insertions, 3 deletions
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 55dcb84ad16..359f1a9cec2 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -138,7 +138,7 @@ use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; use core::mem::{self, ManuallyDrop}; use core::ptr::{self}; -use super::{InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec}; +use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec}; /// Specialization marker for collecting an iterator pipeline into a Vec while reusing the /// source allocation, i.e. executing the pipeline in place. @@ -193,12 +193,16 @@ where // Drop any remaining values at the tail of the source but prevent drop of the allocation // itself once IntoIter goes out of scope. - // If the drop panics then we also leak any elements collected into dst_buf. + // If the drop panics then we also try to drop the destination buffer and its elements. + // This is safe because `forget_allocation_drop_remaining` forgets the allocation *before* + // trying to drop the remaining elements. // // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the // module documenttation why this is ok anyway. + let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap }; src.forget_allocation_drop_remaining(); + mem::forget(dst_guard); let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) }; diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 1b1ef9130fa..25ca33c6a7b 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -22,3 +22,18 @@ impl<T> Drop for InPlaceDrop<T> { } } } + +// A helper struct for in-place collection that drops the destination allocation and elements, +// to avoid leaking them if some other destructor panics. +pub(super) struct InPlaceDstBufDrop<T> { + pub(super) ptr: *mut T, + pub(super) len: usize, + pub(super) cap: usize, +} + +impl<T> Drop for InPlaceDstBufDrop<T> { + #[inline] + fn drop(&mut self) { + unsafe { super::Vec::from_raw_parts(self.ptr, self.len, self.cap) }; + } +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index fa9f2131c0c..acfbb98272d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -125,7 +125,7 @@ use self::set_len_on_drop::SetLenOnDrop; mod set_len_on_drop; #[cfg(not(no_global_oom_handling))] -use self::in_place_drop::InPlaceDrop; +use self::in_place_drop::{InPlaceDrop, InPlaceDstBufDrop}; #[cfg(not(no_global_oom_handling))] mod in_place_drop; |
