From 9a460aac37e91f66f9ba79824dbf62105733efee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Feb 2019 22:10:39 +0100 Subject: [PATCH 01/10] some type-level docs for MaybeUninit; rename into_inner -> into_initialized --- src/libcore/macros.rs | 4 ++-- src/libcore/mem.rs | 45 +++++++++++++++++++++++++++++++++++++++++-- src/libcore/ptr.rs | 4 ++-- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 12b7adb8a9d26..664490c1997ef 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -555,12 +555,12 @@ macro_rules! unimplemented { #[macro_export] #[unstable(feature = "maybe_uninit", issue = "53491")] macro_rules! uninitialized_array { - // This `into_inner` is safe because an array of `MaybeUninit` does not + // This `into_initialized` is safe because an array of `MaybeUninit` does not // require initialization. // FIXME(#49147): Could be replaced by an array initializer, once those can // be any const expression. ($t:ty; $size:expr) => (unsafe { - MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_inner() + MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_initialized() }); } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 8b6d9d882b5ad..998e892bffb26 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1034,7 +1034,41 @@ impl DerefMut for ManuallyDrop { } } -/// A newtype to construct uninitialized instances of `T` +/// A newtype to construct uninitialized instances of `T`. +/// +/// The compiler, in general, assumes that variables are properly initialized +/// at their respective type. For example, a variable of reference type must +/// be aligned and non-NULL. This is an invariant that must *always* be upheld, +/// even in unsafe code. As a consequence, 0-initializing a variable of reference +/// type causes instantaneous undefined behavior, no matter whether that reference +/// ever gets used to access memory: +/// ```rust,ignore +/// use std::mem; +/// +/// let x: &i32 = mem::zeroed(); // undefined behavior! +/// ``` +/// This is exploitet by the compiler for various optimizations, such as eliding +/// run-time checks and optimizing `enum` layout. +/// +/// Not initializing memory at all (instead of 0-initializing it) causes the same +/// issue: after all, the initial value of the variable might just happen to be +/// one that violates the invariant. +/// +/// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data: +/// it is a signal to the compiler indicating that the data here may *not* +/// be initialized: +/// ```rust +/// use std::mem::MaybeUninit; +/// +/// // Create an explicitly uninitialized reference. +/// let mut x = MaybeUninit::<&i32>::uninitialized(); +/// // Set it to a valid value. +/// x.set(&0); +/// // Extract the initialized data -- this is only allowed *after* properly +/// initializing `x`! +/// let x = unsafe { x.into_initialized() }; +/// ``` +/// The compiler then knows to not optimize this code. #[allow(missing_debug_implementations)] #[unstable(feature = "maybe_uninit", issue = "53491")] // NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}` @@ -1101,11 +1135,18 @@ impl MaybeUninit { /// state, otherwise this will immediately cause undefined behavior. #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] - pub unsafe fn into_inner(self) -> T { + pub unsafe fn into_initialized(self) -> T { intrinsics::panic_if_uninhabited::(); ManuallyDrop::into_inner(self.value) } + /// Deprecated alternative to `into_initialized`. Will never get stabilized. + /// Exists only to transition stdsimd to `into_initialized`. + #[inline(always)] + pub(crate) unsafe fn into_inner(self) -> T { + self.into_initialized() + } + /// Get a reference to the contained value. /// /// # Unsafety diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 02eef07afd7ab..537aa92c2cf4e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -573,7 +573,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { pub unsafe fn read(src: *const T) -> T { let mut tmp = MaybeUninit::::uninitialized(); copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - tmp.into_inner() + tmp.into_initialized() } /// Reads the value from `src` without moving it. This leaves the @@ -642,7 +642,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); - tmp.into_inner() + tmp.into_initialized() } /// Overwrites a memory location with the given value without reading or From 760424af17bc40c4fd2be95e96ebcebe70d217e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Feb 2019 22:11:28 +0100 Subject: [PATCH 02/10] expand as_[mut_]ptr docs a bit --- src/libcore/mem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 998e892bffb26..3348e774a0b7a 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1174,16 +1174,16 @@ impl MaybeUninit { &mut *self.value } - /// Get a pointer to the contained value. Reading from this pointer will be undefined - /// behavior unless the `MaybeUninit` is initialized. + /// Get a pointer to the contained value. Reading from this pointer or turning it + /// into a reference will be undefined behavior unless the `MaybeUninit` is initialized. #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] pub fn as_ptr(&self) -> *const T { unsafe { &*self.value as *const T } } - /// Get a mutable pointer to the contained value. Reading from this pointer will be undefined - /// behavior unless the `MaybeUninit` is initialized. + /// Get a mutable pointer to the contained value. Reading from this pointer or turning it + /// into a reference will be undefined behavior unless the `MaybeUninit` is initialized. #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] pub fn as_mut_ptr(&mut self) -> *mut T { From f8c7d8dc8e8f779e6468e83f79456ed1916a93d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Feb 2019 22:14:14 +0100 Subject: [PATCH 03/10] make set return a mutable reference --- src/libcore/mem.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 3348e774a0b7a..4712df1fa7cd2 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1117,11 +1117,14 @@ impl MaybeUninit { } /// Set the value of the `MaybeUninit`. This overwrites any previous value without dropping it. + /// For your convenience, this also returns a mutable reference to the (now + /// safely initialized) content of `self`. #[unstable(feature = "maybe_uninit", issue = "53491")] #[inline(always)] - pub fn set(&mut self, val: T) { + pub fn set(&mut self, val: T) -> &mut T { unsafe { self.value = ManuallyDrop::new(val); + self.get_mut() } } From 789b4d1a4f9a4c0cfbce51f0939b5ec322abca0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Feb 2019 11:11:39 +0100 Subject: [PATCH 04/10] typos --- src/libcore/mem.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 4712df1fa7cd2..68f985ce65202 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1047,7 +1047,7 @@ impl DerefMut for ManuallyDrop { /// /// let x: &i32 = mem::zeroed(); // undefined behavior! /// ``` -/// This is exploitet by the compiler for various optimizations, such as eliding +/// This is exploited by the compiler for various optimizations, such as eliding /// run-time checks and optimizing `enum` layout. /// /// Not initializing memory at all (instead of 0-initializing it) causes the same @@ -1055,7 +1055,7 @@ impl DerefMut for ManuallyDrop { /// one that violates the invariant. /// /// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data: -/// it is a signal to the compiler indicating that the data here may *not* +/// it is a signal to the compiler indicating that the data here might *not* /// be initialized: /// ```rust /// use std::mem::MaybeUninit; From aaafc3c7fa1846b952b1a479ed69420b9b3f86bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 17:22:46 +0100 Subject: [PATCH 05/10] fix doctest --- src/libcore/mem.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 68f985ce65202..18302e36ff762 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1042,7 +1042,7 @@ impl DerefMut for ManuallyDrop { /// even in unsafe code. As a consequence, 0-initializing a variable of reference /// type causes instantaneous undefined behavior, no matter whether that reference /// ever gets used to access memory: -/// ```rust,ignore +/// ```rust,no_run /// use std::mem; /// /// let x: &i32 = mem::zeroed(); // undefined behavior! @@ -1065,7 +1065,7 @@ impl DerefMut for ManuallyDrop { /// // Set it to a valid value. /// x.set(&0); /// // Extract the initialized data -- this is only allowed *after* properly -/// initializing `x`! +/// // initializing `x`! /// let x = unsafe { x.into_initialized() }; /// ``` /// The compiler then knows to not optimize this code. From d371bcefb58d28caa585e77258747bcb0aba89b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 21:22:11 +0100 Subject: [PATCH 06/10] fix test case --- src/test/run-pass/panic-uninitialized-zeroed.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs index d47ff6c630d11..31c0d2994d415 100644 --- a/src/test/run-pass/panic-uninitialized-zeroed.rs +++ b/src/test/run-pass/panic-uninitialized-zeroed.rs @@ -36,7 +36,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_inner() + mem::MaybeUninit::::uninitialized().into_initialized() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type !" })), @@ -63,7 +63,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_inner() + mem::MaybeUninit::::uninitialized().into_initialized() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type Foo" })), @@ -90,7 +90,7 @@ fn main() { assert_eq!( panic::catch_unwind(|| { - mem::MaybeUninit::::uninitialized().into_inner() + mem::MaybeUninit::::uninitialized().into_initialized() }).err().and_then(|a| a.downcast_ref::().map(|s| { s == "Attempted to instantiate uninhabited type Bar" })), From b331b86d308d09398cf6202f367ea0f02babe523 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 22:26:30 +0100 Subject: [PATCH 07/10] extend box-maybe-uninit test --- src/test/codegen/box-maybe-uninit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs index a7fb74c04731d..ad1d259a0da21 100644 --- a/src/test/codegen/box-maybe-uninit.rs +++ b/src/test/codegen/box-maybe-uninit.rs @@ -9,5 +9,8 @@ use std::mem::MaybeUninit; pub fn box_uninitialized() -> Box> { // CHECK-LABEL: @box_uninitialized // CHECK-NOT: store + // CHECK-NOT: alloca + // CHECK-NOT: memcpy + // CHECK-NOT: memset Box::new(MaybeUninit::uninitialized()) } From f3eede6870c817e2e22782ad08d31fcaa8c6b640 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:14:12 +0100 Subject: [PATCH 08/10] fix doctests --- src/libcore/mem.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 18302e36ff762..930fe737a7264 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1045,7 +1045,7 @@ impl DerefMut for ManuallyDrop { /// ```rust,no_run /// use std::mem; /// -/// let x: &i32 = mem::zeroed(); // undefined behavior! +/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! /// ``` /// This is exploited by the compiler for various optimizations, such as eliding /// run-time checks and optimizing `enum` layout. @@ -1058,6 +1058,7 @@ impl DerefMut for ManuallyDrop { /// it is a signal to the compiler indicating that the data here might *not* /// be initialized: /// ```rust +/// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// // Create an explicitly uninitialized reference. From 4853ce660e38f6dd2e686e2c6292f6e004f51d91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Feb 2019 15:27:59 +0100 Subject: [PATCH 09/10] it is okay not to use into_inner --- src/libcore/mem.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 930fe737a7264..3e081b4f0a46a 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1147,6 +1147,7 @@ impl MaybeUninit { /// Deprecated alternative to `into_initialized`. Will never get stabilized. /// Exists only to transition stdsimd to `into_initialized`. #[inline(always)] + #[allow(unused)] pub(crate) unsafe fn into_inner(self) -> T { self.into_initialized() } From 4833074a9a47c12bcfeee4435bf981981ede689c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Feb 2019 19:08:49 +0100 Subject: [PATCH 10/10] fix SGX build failures --- src/libstd/sys/sgx/ext/arch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs index 3bd87b5d26574..97f7d9181a539 100644 --- a/src/libstd/sys/sgx/ext/arch.rs +++ b/src/libstd/sys/sgx/ext/arch.rs @@ -41,7 +41,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> ); match error { - 0 => Ok(out.into_inner()), + 0 => Ok(out.into_initialized()), err => Err(err), } } @@ -69,6 +69,6 @@ pub fn ereport( "{rdx}"(report.as_mut_ptr()) ); - report.into_inner() + report.into_initialized() } }