From 2305012e6a819805fdcf9207d865fa4dbda58f81 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 20 Dec 2024 19:20:23 +0100 Subject: [PATCH] docs: `transmute<&mut T, &mut MaybeUninit>` is unsound when exposed to safe code In the playground the example program terminates with an unpredictable exit code. The undefined behavior is also detected by miri: error: Undefined Behavior: using uninitialized data --- library/core/src/mem/maybe_uninit.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 9b3d690209856..58fb5be5812c8 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -232,6 +232,26 @@ use crate::{fmt, intrinsics, ptr, slice}; /// remain `#[repr(transparent)]`. That said, `MaybeUninit` will *always* guarantee that it has /// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that /// guarantee may evolve. +/// +/// Note that even though `T` and `MaybeUninit` are ABI compatible it is still unsound to +/// transmute `&mut T` to `&mut MaybeUninit` and expose that to safe code because it would allow +/// safe code to access uninitialized memory: +/// +/// ```rust,no_run +/// use core::mem::MaybeUninit; +/// +/// fn unsound_transmute(val: &mut T) -> &mut MaybeUninit { +/// unsafe { core::mem::transmute(val) } +/// } +/// +/// fn main() { +/// let mut code = 0; +/// let code = &mut code; +/// let code2 = unsound_transmute(code); +/// *code2 = MaybeUninit::uninit(); +/// std::process::exit(*code); // UB! Accessing uninitialized memory. +/// } +/// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] // Lang item so we can wrap other types in it. This is useful for coroutines. #[lang = "maybe_uninit"]