What can happen when accessing uninitialised memory?

I am using serde to save and load a struct that has an array that may or may not be initialised.

#[repr(C)]
pub struct MyStruct {
    array: [MaybeUninit<f32>; 3],
    is_initialized: bool,
}

The way I save it is by transmuting it to a struct that has the same layout but isn't MaybeUninit:

#[derive(Serialize, Deserialize)]
#[repr(C)]
struct Intermediary {
    array: [f32; 3],
    is_initialized: bool,
}

This Intermediary struct I can save and load easily. When I do this miri complains for accessing uninitialised memory (rightly so).

The only way to access the array from outside my library is through functions that make sure that the array is initialised. What exactly can go wrong if I do this?

Can you make the struct be a repr(C) enum instead? Using 2195-really-tagged-unions - The Rust RFC Book.

Then you wouldn't need to deal in MaybeUninit in Rust at all, and serde could just serialize it.

The MyStruct struct is actually a data structure that for memory size reasons can't afford to have the extra data that an enum needs.

To answer the OP, it's UB and it's worse than whatever you can imagine.

2 Likes

The short answer is that any program that reads uninitialized memory is allowed to do literally anything.

3 Likes