Another Experiment To Make Unsafe Rust Safer: Preventing UB In MaybeUninit With Compile Time Error
Rust Internals [Unofficial]
May 22, 2026
Hello, I'm doing this experiment. What do you guys think? :]
use std::mem::MaybeUninit;
use std::marker::PhantomData;
pub struct Uninit;
pub struct Init;
pub struct UninitStorage<T>(MaybeUninit<T>);
pub struct InitStorage<T>(MaybeUninit<T>);
impl<T> Drop for InitStorage<T> {
fn drop(&mut self) {
unsafe {
self.0.assume_init_drop();
}
}
}
pub struct UninitGuard<T, State> {
storage: State,
_marker: PhantomData<T>,
}
#[diagnostic::on_unimplemented(
message = "Illegal access: Memory is not initialized yet!",
label = "Attempted to operate on data here, but the status is still `Uninit`",
note = "Call `.write(val)` on the UninitGuard first before accessing its references or pointers."
)]
pub trait IsInitialized<State> {}
#[diagnostic::do_not_recommend]
impl<T> IsInitialized<InitStorage<T>> for UninitGuard<T, InitStorage<T>> {}
impl<T> UninitGuard<T, UninitStorage<T>> {
pub fn new() -> Self {
Self {
storage: UninitStorage(MaybeUninit::uninit()),
_marker: PhantomData,
}
}
pub fn zeroed() -> Self {
Self {
storage: UninitStorage(MaybeUninit::zeroed()),
_marker: PhantomData,
}
}
pub const fn uninit() -> Self {
Self {
storage: UninitStorage(MaybeUninit::uninit()),
_marker: PhantomData,
}
}
pub fn write(self, val: T) -> UninitGuard<T, InitStorage<T>> {
let mut storage = MaybeUninit::uninit();
storage.write(val);
UninitGuard {
storage: InitStorage(storage),
_marker: PhantomData,
}
}
}
impl<T, State> UninitGuard<T, State>
where
Self: IsInitialized<State>,
{
pub fn as_ptr(&self) -> *const T {
let storage = unsafe { &*( &self.storage as *const State as *const MaybeUninit<T> ) };
storage.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut T {
let storage = unsafe { &mut *( &mut self.storage as *mut State as *mut MaybeUninit<T> ) };
storage.as_mut_ptr()
}
pub fn get_ref(&self) -> &T {
let storage = unsafe { &*( &self.storage as *const State as *const MaybeUninit<T> ) };
unsafe { storage.assume_init_ref() }
}
pub fn get_mut(&mut self) -> &mut T {
let storage = unsafe { &mut *( &mut self.storage as *mut State as *mut MaybeUninit<T> ) };
unsafe { storage.assume_init_mut() }
}
pub fn assume_init(self) -> T {
let mut this = std::mem::ManuallyDrop::new(self);
let storage = unsafe { &mut *( &mut this.storage as *mut State as *mut MaybeUninit<T> ) };
unsafe { storage.assume_init_read() }
}
pub fn replace(&mut self, val: T) -> T {
let storage = unsafe { &mut *( &mut self.storage as *mut State as *mut MaybeUninit<T> ) };
let old = unsafe { storage.assume_init_read() };
storage.write(val);
old
}
}
impl<T> UninitGuard<T, InitStorage<T>> {
pub const fn new_init(val: T) -> Self {
Self {
storage: InitStorage(MaybeUninit::new(val)),
_marker: PhantomData,
}
}
}
fn a() {
let guard = UninitGuard::<String, _>::new();
let tes = guard.assume_init();
}
fn main() {
}
It will cause compile time error if we call assume_init, get reference, get pointer when the memory is uninitialized yet
Compiling playground v0.0.1 (/playground)
error[E0599]: Illegal access: Memory is not initialized yet!
--> src/main.rs:115:21
|
19 | pub struct UninitGuard<T, State> {
| -------------------------------- method `assume_init` not found for this struct because it doesn't satisfy `_: IsInitialized<UninitStorage<String>>`
...
115 | let tes = guard.assume_init();
| ^^^^^^^^^^^ Attempted to operate on data here, but the status is still `Uninit`
|
note: trait bound `UninitGuard<String, UninitStorage<String>>: IsInitialized<UninitStorage<String>>` was not satisfied
--> src/main.rs:68:11
|
66 | impl<T, State> UninitGuard<T, State>
| ---------------------
67 | where
68 | Self: IsInitialized<State>,
| ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
= note: Call `.write(val)` on the UninitGuard first before accessing its references or pointers.
note: the trait `IsInitialized` must be implemented
--> src/main.rs:29:1
|
29 | pub trait IsInitialized<State> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Standard Output
What is the escape hatch that you guys spot in this code?
If this experiment is successful, it would be a valuable addition to the standard library. Because it prevents many UBs that are related to uninitialized memory
Discussion in the ATmosphere