diff options
| author | bors <bors@rust-lang.org> | 2021-03-13 07:06:01 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-03-13 07:06:01 +0000 |
| commit | ec487bf3cfc9ce386da25169509fae8f2b4d4eec (patch) | |
| tree | d8468854e836ef1fad5b8b9146c272e98fd5dad5 /library/alloc/src | |
| parent | f42888c15fd370b8bca4c5646ffc3aac3005dca8 (diff) | |
| parent | 1f031d95ded44337848f53e07aae05087ccf15f1 (diff) | |
| download | rust-ec487bf3cfc9ce386da25169509fae8f2b4d4eec.tar.gz rust-ec487bf3cfc9ce386da25169509fae8f2b4d4eec.zip | |
Auto merge of #82760 - WaffleLapkin:unleak_extend_from_within, r=kennytm
Fix leak in Vec::extend_from_within Fixes #82533
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 0028e290fac..49758f672a8 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1942,6 +1942,18 @@ impl<T, A: Allocator> Vec<T, A> { #[unstable(feature = "vec_split_at_spare", issue = "81944")] #[inline] pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [MaybeUninit<T>]) { + // SAFETY: + // - len is ignored and so never changed + let (init, spare, _) = unsafe { self.split_at_spare_mut_with_len() }; + (init, spare) + } + + /// Safety: changing returned .2 (&mut usize) is considered the same as calling `.set_len(_)`. + /// + /// This method is used to have unique access to all vec parts at once in `extend_from_within`. + unsafe fn split_at_spare_mut_with_len( + &mut self, + ) -> (&mut [T], &mut [MaybeUninit<T>], &mut usize) { let Range { start: ptr, end: spare_ptr } = self.as_mut_ptr_range(); let spare_ptr = spare_ptr.cast::<MaybeUninit<T>>(); let spare_len = self.buf.capacity() - self.len; @@ -1953,7 +1965,7 @@ impl<T, A: Allocator> Vec<T, A> { let initialized = slice::from_raw_parts_mut(ptr, self.len); let spare = slice::from_raw_parts_mut(spare_ptr, spare_len); - (initialized, spare) + (initialized, spare, &mut self.len) } } } @@ -2165,22 +2177,23 @@ trait ExtendFromWithinSpec { impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> { default unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) { - let initialized = { - let (this, spare) = self.split_at_spare_mut(); - - // SAFETY: - // - caller guaratees that src is a valid index - let to_clone = unsafe { this.get_unchecked(src) }; - - to_clone.iter().cloned().zip(spare.iter_mut()).map(|(e, s)| s.write(e)).count() - }; + // SAFETY: + // - len is increased only after initializing elements + let (this, spare, len) = unsafe { self.split_at_spare_mut_with_len() }; // SAFETY: - // - elements were just initialized - unsafe { - let new_len = self.len() + initialized; - self.set_len(new_len); - } + // - caller guaratees that src is a valid index + let to_clone = unsafe { this.get_unchecked(src) }; + + to_clone + .iter() + .cloned() + .zip(spare.iter_mut()) + .map(|(src, dst)| dst.write(src)) + // Note: + // - Element was just initialized with `MaybeUninit::write`, so it's ok to increace len + // - len is increased after each element to prevent leaks (see issue #82533) + .for_each(|_| *len += 1); } } |
