From 836e264dc5d91830573a8178f72ba914ae0e624e Mon Sep 17 00:00:00 2001 From: mosh Date: Fri, 10 Apr 2020 09:47:27 +0900 Subject: [PATCH 1/2] Add Vec::get_uninit_unchecked --- src/liballoc/vec.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 7ef281ff208d7..bd5337c08deca 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -66,7 +66,7 @@ use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; -use core::mem::{self, ManuallyDrop}; +use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Index, IndexMut, RangeBounds}; use core::ptr::{self, NonNull}; @@ -854,6 +854,42 @@ impl Vec { ptr } + /// Returns a mutable reference to an element, without doing bounds + /// checking. + /// + /// This is generally not recommended, use with caution! + /// Calling this method with an out-of-allocation index is *[undefined behavior]* + /// even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_get_uninit_unchecked, maybe_uninit_extra)] + /// + /// // Allocate vector big enough for 4 elements. + /// let size = 4; + /// let mut x = Vec::with_capacity(4); + /// + /// // Initialize elements via raw pointer writes, then set length. + /// unsafe { + /// for i in 0..size { + /// x.get_uninit_unchecked(i).write(i as i32); + /// } + /// x.set_len(size); + /// } + /// assert_eq!(&*x, &[0, 1, 2, 3]); + /// ``` + #[unstable(feature = "vec_get_uninit_unchecked", issue = "none")] + pub fn get_uninit_unchecked(&mut self, index: usize) -> &mut MaybeUninit { + if cfg!(debug_assertions) && index >= self.capacity() { + panic!("Out of allocation access") + } else { + unsafe { &mut *(self.as_mut_ptr().add(index) as *mut MaybeUninit) } + } + } + /// Forces the length of the vector to `new_len`. /// /// This is a low-level operation that maintains none of the normal From 45077aa0bf01f362b88a486dddf9f2a096b0f51f Mon Sep 17 00:00:00 2001 From: mosh Date: Fri, 10 Apr 2020 23:52:05 +0900 Subject: [PATCH 2/2] Reflect suggested changes* Add unsafe* Use debug_assert instead of cfg* Improve the explanation in the assertion* UB and memory leak notes --- src/liballoc/vec.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index bd5337c08deca..f3f0a430d1c78 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -860,8 +860,15 @@ impl Vec { /// This is generally not recommended, use with caution! /// Calling this method with an out-of-allocation index is *[undefined behavior]* /// even if the resulting reference is not used. + /// When you asign [`MaybeUninit::uninit()`] to the index in bounds, it is + /// *[undefined behavior]* to call other methods or drop the vector before using [`set_len`] + /// to make the index out of bounds. + /// You can have a memory leak if you forget to use [`set_len`] to make the index in bounds + /// after asigning value to the reference out of bounds. /// /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`MaybeUninit::uninit()`]: ../mem/union.MaybeUninit.html#method.uninit + /// [`set_len`]: #method.set_len /// /// # Examples /// @@ -882,12 +889,14 @@ impl Vec { /// assert_eq!(&*x, &[0, 1, 2, 3]); /// ``` #[unstable(feature = "vec_get_uninit_unchecked", issue = "none")] - pub fn get_uninit_unchecked(&mut self, index: usize) -> &mut MaybeUninit { - if cfg!(debug_assertions) && index >= self.capacity() { - panic!("Out of allocation access") - } else { - unsafe { &mut *(self.as_mut_ptr().add(index) as *mut MaybeUninit) } - } + pub unsafe fn get_uninit_unchecked(&mut self, index: usize) -> &mut MaybeUninit { + debug_assert!( + index < self.capacity(), + "index out of allocation: the capacity is {} but the index is {}", + self.capacity(), + index + ); + &mut *(self.as_mut_ptr().add(index) as *mut MaybeUninit) } /// Forces the length of the vector to `new_len`.