How to modify possibly-uninitialized memory without UB?

I'm trying to create a MangledBox which would heap-store bytes of T XORed with a random key. Unfortunately, once I write T there might have been some padding introduced, and it seems no longer possible to XOR the bytes back.

struct MangledBox<T: Sized> {
    data: NonNull<MaybeUninit<T>>,
    key: MaybeUninit<T>,
}

impl<T: Sized> MangledBox<T> {
    pub fn new() -> Self {
        let mut key = MaybeUninit::uninit();
        getrandom::fill_uninit(key.as_bytes_mut()).expect("no keygen");
        Self {
            data: Box::into_non_null(Box::new_zeroed()),
            key,
        }
    }

    pub fn with_unmangled<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(NonNull<T>) -> R,
    {
        let data_ptr = self.data.as_ptr().cast::<u8>();
        let key_ptr = self.key.as_ptr().cast::<u8>();
        
        for i in 0..size_of::<T>() {
            let key_byte = unsafe {*key_ptr.wrapping_add(i)};
            let data_byte = ???;
            unsafe {data_ptr.write_volatile(data_byte ^ key_byte);}
        }
        todo!("omitted for brevity")
    }
}

Is there no freeze or similar function which would allow working with the range?

There is, as of yet, no non-UB way to read uninitialized data in a typed fashion.[1] There's no exposed llvm freeze. So you need to limit the types with something like bytemuck's NoUninit. Probably you just want to use bytemuck or zerocopy's functionality as they're designed for these sorts of use cases.

Here's one related issue. There are other more direct conversations, but they're a pain to search for.


  1. Some want it, some want to never allow it. ↩︎

In fact I don't need to read uninitialized memory to Rust per se (if there were intrinsics to just do arithmetics and put it back in place), but that stance is understandable.

bytemuck is fine, better solution than I expected! Incidentally, Strings and references don't implement bytemuck::NoUninit which fits my MangledBox perfectly: there's not much point in masking pointers rather than data.