Not initializing a value [in a safe context]

Let's say you have a case like this:

fn read_u32<R>(reader: &mut R, crc32: &mut Hasher) -> Result<u32, Error>
where
  R: std::io::Read
{
  let mut wordbuf: [u8; 4] = [0, 0, 0, 0];
  if reader.read_exact(&mut wordbuf).is_ok() {
    crc32.update(&wordbuf);
    Ok(u32::from_be_bytes(wordbuf))
  } else {
    Err(Error:IO(String::from("read_exact failed")))
  }
}

And let's assume that we know, with 100% certainty, that read_exact() does exactly what it implies, and if it ever fails, we'll return from the function with an error. Under these assumptions, we don't actually need to initialize wordbuf to [0, 0, 0, 0], because an uninitialized read will never actually happen.

Now let's say this unnecessary (again, under the assumption it can truly be shown to be unnecessary) initialization would actually be measurable, and one would want to eliminate it -- how would one go about doing that? Is this the sort of thing that MaybeUninit is used for?

This is how you would do it:

fn read_u32<R>(reader: &mut R, crc32: &mut Hasher) -> Result<u32, Error>
where
    R: std::io::Read,
{
    let mut wordbuf: MaybeUninit<[u8; 4]> = MaybeUninit::uninit();
    if reader.read_exact(unsafe { &mut *wordbuf.as_mut_ptr() }).is_ok() {
        let wordbuf = unsafe { wordbuf.assume_init() };
        crc32.update(&wordbuf);
        Ok(u32::from_be_bytes(wordbuf))
    } else {
        Err(Error::IO(String::from("read_exact failed")))
    }
}

Unfortunately, doing this when R is a generic parameter you don't control is not correct because the reader could try to read the values in the &mut [u8] you pass it, which is definitely not ok, and since the implementation of the reader doesn't require the unsafe keyword, you are the one at fault if that happens.

3 Likes

There is an accepted RFC describing improved support in std for performing read-into-uninitialized soundly:

https://rust-lang.github.io/rfcs/2930-read-buf.html

(Unfortunately the name ReadBuf is really confusing; I hope they change it before the feature stabilizes.)

2 Likes

Tokio already uses the approach described in that RFC for their async IO traits.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.