Skip to main content

minimally_init

Function minimally_init 

Source
pub(crate) fn minimally_init(buf: &mut [MaybeUninit<u8>]) -> &mut [u8] 
Expand description

When we only care about writing to a slice but &mut [u8] grants the read capability and reading would be UB, this function does the minimum writing to make the slice have arbitrary but fixed-value bytes. This maintains correct boundary between unsafe and safe in terms of UB avoidance resposibility even though we don’t actually perform reads. The caller must not rely on any byte in the slice that was already initialized to retain its value after this function returns.

The point of wishing to not to contaminate all places with &mut [MaybeUninit<u8>] is that &mut [u8] interacts better with core::simd in a way that doesn’t require unsafe in more places.

Note that the caller has to overwrite the exposed arbitrary but fixed-value bytes to avoid information disclosure (somewhat analogously to reusing an intermediate buffer created without any unsafe). This function is not unsafe, because this function does not let the caller to experience UB. Letting &mut [MaybeUninit<u8>] show up in more places in the crate internals would not change the information disclosure risk in case there’s a bug in the tracking of how much has been written. Either way, the tracking of how much has been written has to actually work, but it has a very good track record of working.

On M3 Pro, we could just zero-initialize every byte without a notable performance penalty, but on Zen 3 and Skylake, zeroing all bytes carries a measurable penalty (in some cases only; depending on details of subsequent writes!) but zeroing the first byte of every page does not carry this perf penalty compared to not initializing anything (at least when the slice is reasonable-sized relative to what meaningful data end up written into it later).