Skip to content

Commit 6ade237

Browse files
authored
Rollup merge of #134583 - Enselic:maybe-uninit-transmute, r=workingjubilee
docs: `transmute<&mut T, &mut MaybeUninit<T>>` is unsound when exposed to safe code Closes #66699 On my system (Edit: And also in the [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=90529e2a9900599cb759e4bfaa5b5efe)) the example program terminates with an unpredictable exit code: ```console $ cargo +nightly build && target/debug/bin ; echo $? 255 $ cargo +nightly build && target/debug/bin ; echo $? 253 ``` And miri considers the code to have undefined behavior: ```console $ cargo +nightly miri run error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> src/main.rs:12:24 | 12 | std::process::exit(*code); // UB! Accessing uninitialized memory | ^^^^^ using uninitialized data, but this operation requires initialized memory | error: aborting due to 1 previous error ```
2 parents bd160f1 + 2305012 commit 6ade237

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

Diff for: library/core/src/mem/maybe_uninit.rs

+20
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,26 @@ use crate::{fmt, intrinsics, ptr, slice};
232232
/// remain `#[repr(transparent)]`. That said, `MaybeUninit<T>` will *always* guarantee that it has
233233
/// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that
234234
/// guarantee may evolve.
235+
///
236+
/// Note that even though `T` and `MaybeUninit<T>` are ABI compatible it is still unsound to
237+
/// transmute `&mut T` to `&mut MaybeUninit<T>` and expose that to safe code because it would allow
238+
/// safe code to access uninitialized memory:
239+
///
240+
/// ```rust,no_run
241+
/// use core::mem::MaybeUninit;
242+
///
243+
/// fn unsound_transmute<T>(val: &mut T) -> &mut MaybeUninit<T> {
244+
/// unsafe { core::mem::transmute(val) }
245+
/// }
246+
///
247+
/// fn main() {
248+
/// let mut code = 0;
249+
/// let code = &mut code;
250+
/// let code2 = unsound_transmute(code);
251+
/// *code2 = MaybeUninit::uninit();
252+
/// std::process::exit(*code); // UB! Accessing uninitialized memory.
253+
/// }
254+
/// ```
235255
#[stable(feature = "maybe_uninit", since = "1.36.0")]
236256
// Lang item so we can wrap other types in it. This is useful for coroutines.
237257
#[lang = "maybe_uninit"]

0 commit comments

Comments
 (0)