Skip to content

Commit 48316df

Browse files
committed
Auto merge of #99182 - RalfJung:mitigate-uninit, r=scottmcm
mem::uninitialized: mitigate many incorrect uses of this function Alternative to #98966: fill memory with `0x01` rather than leaving it uninit. This is definitely bitewise valid for all `bool` and nonnull types, and also those `Option<&T>` that we started putting `noundef` on. However it is still invalid for `char` and some enums, and on references the `dereferenceable` attribute is still violated, so the generated LLVM IR still has UB -- but in fewer cases, and `dereferenceable` is hopefully less likely to cause problems than clearly incorrect range annotations. This can make using `mem::uninitialized` a lot slower, but that function has been deprecated for years and we keep telling everyone to move to `MaybeUninit` because it is basically impossible to use `mem::uninitialized` correctly. For the cases where that hasn't helped (and all the old code out there that nobody will ever update), we can at least mitigate the effect of using this API. Note that this is *not* in any way a stable guarantee -- it is still UB to call `mem::uninitialized::<bool>()`, and Miri will call it out as such. This is somewhat similar to #87032, which proposed to make `uninitialized` return a buffer filled with 0x00. However - That PR also proposed to reduce the situations in which we panic, which I don't think we should do at this time. - The 0x01 bit pattern means that nonnull requirements are satisfied, which (due to references) is the most common validity invariant. `@5225225` I hope I am using `cfg(sanitize)` the right way; I was not sure for which ones to test here. Cc #66151 Fixes #87675
2 parents ada80a1 + 7b41494 commit 48316df

File tree

2 files changed

+12
-1
lines changed

2 files changed

+12
-1
lines changed

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164
#![feature(allow_internal_unstable)]
165165
#![feature(associated_type_bounds)]
166166
#![feature(auto_traits)]
167+
#![feature(cfg_sanitize)]
167168
#![feature(cfg_target_has_atomic)]
168169
#![feature(cfg_target_has_atomic_equal_alignment)]
169170
#![feature(const_fn_floating_point_arithmetic)]

library/core/src/mem/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,8 @@ pub unsafe fn zeroed<T>() -> T {
654654
/// produce a value of type `T`, while doing nothing at all.
655655
///
656656
/// **This function is deprecated.** Use [`MaybeUninit<T>`] instead.
657+
/// It also might be slower than using `MaybeUninit<T>` due to mitigations that were put in place to
658+
/// limit the potential harm caused by incorrect use of this function in legacy code.
657659
///
658660
/// The reason for deprecation is that the function basically cannot be used
659661
/// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit].
@@ -683,7 +685,15 @@ pub unsafe fn uninitialized<T>() -> T {
683685
// SAFETY: the caller must guarantee that an uninitialized value is valid for `T`.
684686
unsafe {
685687
intrinsics::assert_uninit_valid::<T>();
686-
MaybeUninit::uninit().assume_init()
688+
let mut val = MaybeUninit::<T>::uninit();
689+
690+
// Fill memory with 0x01, as an imperfect mitigation for old code that uses this function on
691+
// bool, nonnull, and noundef types. But don't do this if we actively want to detect UB.
692+
if !cfg!(any(miri, sanitize = "memory")) {
693+
val.as_mut_ptr().write_bytes(0x01, 1);
694+
}
695+
696+
val.assume_init()
687697
}
688698
}
689699

0 commit comments

Comments
 (0)