diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 866cd5ec535d2..3e960a28af90a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -163,6 +163,7 @@ #![feature(slice_ptr_get)] #![feature(no_niche)] // rust-lang/rust#68303 #![feature(no_coverage)] // rust-lang/rust#84605 +#![feature(cfg_sanitize)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(or_patterns_back_compat)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 5bf47c3951da2..23a164eb4ccfa 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -627,12 +627,22 @@ pub unsafe fn zeroed() -> T { } } -/// Bypasses Rust's normal memory-initialization checks by pretending to -/// produce a value of type `T`, while doing nothing at all. -/// -/// **This function is deprecated.** Use [`MaybeUninit`] instead. -/// -/// The reason for deprecation is that the function basically cannot be used +/// **This function is deprecated with extreme prejudice.** +/// It is replaced by [`MaybeUninit`], which must be used instead of this function. +/// +/// This function produces a value of type `T` that may be of any imaginable +/// bit representation in memory. +/// The exact value that is produced by this function is subject to no +/// guarantees whatsoever, and cannot be relied upon. +/// The value returned by this function may differ between implementations, +/// between different versions of the same implementation, +/// between different compilations of the exact same code with the exact same compiler, +/// between different executions of the same program, +/// between different invocations within a single program, +/// between different *uses* of the same returned value, +/// or for any other reason whatsoever, with no warning. +/// +/// The reason this function is deprecated is that it basically cannot be used /// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit]. /// As the [`assume_init` documentation][assume_init] explains, /// [the Rust compiler assumes][inv] that values are properly initialized. @@ -645,21 +655,40 @@ pub unsafe fn zeroed() -> T { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// +/// Note: because of the aforementioned lack of guarantee about the values returned +/// by this function, and because of the aforementioned inherent unsafety of this API, +/// it is legal for an implementation of Rust to return initialized memory from +/// this function if it so chooses, as a last-ditch safety net. +/// To emphatically reiterate, neither this behavior nor the exact value of any +/// initialized memory may be relied upon. +/// If truly uninitialized memory is desired, then `MaybeUninit` must be used. +/// /// [uninit]: MaybeUninit::uninit /// [assume_init]: MaybeUninit::assume_init /// [inv]: MaybeUninit#initialization-invariant #[inline(always)] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] pub unsafe fn uninitialized() -> T { + // Under sanitizers we actually return uninitialized memory, + // as they should be able to check for improper use. + #[cfg(any(miri, sanitize = "memory"))] // SAFETY: the caller must guarantee that an unitialized value is valid for `T`. unsafe { intrinsics::assert_uninit_valid::(); MaybeUninit::uninit().assume_init() } + + // When not being sanitized we paper over the problems with this API by returning + // initialized memory, so that legacy code isn't broken + // and has an actual chance to be safe. + #[cfg(not(any(miri, sanitize = "memory")))] + // SAFETY: Because an uninitialized value does not guarantee any specific bit + // representation, it is therefore no less safe to return a zeroed value. + unsafe { + zeroed::() + } } /// Swaps the values at two mutable locations, without deinitializing either one. diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 72c0d7913e525..68e2ca2fbd14b 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -105,7 +105,7 @@ fn main() { // Types that do not like zero-initialziation test_panic_msg( || mem::uninitialized::(), - "attempted to leave type `fn()` uninitialized, which is invalid" + "attempted to zero-initialize type `fn()`, which is invalid" ); test_panic_msg( || mem::zeroed::(), @@ -114,7 +114,7 @@ fn main() { test_panic_msg( || mem::uninitialized::<*const dyn Send>(), - "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid" + "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" ); test_panic_msg( || mem::zeroed::<*const dyn Send>(), @@ -145,7 +145,7 @@ fn main() { test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), - "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ + "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ which is invalid" ); test_panic_msg( @@ -156,7 +156,7 @@ fn main() { test_panic_msg( || mem::uninitialized::(), - "attempted to leave type `OneVariant_NonZero` uninitialized, \ + "attempted to zero-initialize type `OneVariant_NonZero`, \ which is invalid" ); test_panic_msg( @@ -167,7 +167,7 @@ fn main() { test_panic_msg( || mem::uninitialized::(), - "attempted to leave type `NoNullVariant` uninitialized, \ + "attempted to zero-initialize type `NoNullVariant`, \ which is invalid" ); test_panic_msg( @@ -176,20 +176,6 @@ fn main() { which is invalid" ); - // Types that can be zero, but not uninit. - test_panic_msg( - || mem::uninitialized::(), - "attempted to leave type `bool` uninitialized, which is invalid" - ); - test_panic_msg( - || mem::uninitialized::(), - "attempted to leave type `LR` uninitialized, which is invalid" - ); - test_panic_msg( - || mem::uninitialized::>(), - "attempted to leave type `std::mem::ManuallyDrop` uninitialized, which is invalid" - ); - // Some things that should work. let _val = mem::zeroed::(); let _val = mem::zeroed::();