How to pass an uninitialized data to a function which takes a &mut [T]?

I'm trying to figure out the right way to pass an uninitialized array to an external function which fills some of its elements and returns the number of elements that were initialized.

Is the following code correct? Is there a better way to achieve this on stable Rust? I checked with miri and it does not seem to complain but slice is a reference to uninitialized data so I'm suspicious. If this is correct - what is the safety reasoning for the line which binds slice? If not correct - what is the right way to do it?

Thanks

use std::mem::MaybeUninit;

/// Fills the buffer with data, returns the number of elements written. This is just an example for a 3rd party crate function (maybe some FFI wrapper).
unsafe fn InsertStuffInBuffer(buf: &mut [u16]) -> usize;

fn main() {
    let mut buf = MaybeUninit::<[u16; 260]>::uninit();

    let slice = unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u16, 260) };
    let len = unsafe { InsertStuffInBuffer(slice) };

    let buf = unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u16, len) };

    println!("{:?}", buf);
}

This is UB. &mut [u16] assumes that everything in that slice is initialized. Not sure what miri test you ran, but a naive implementation where InsertStuffInBuffer accesses anything in buf errors.

You can't pass uninitialized data where a &mut [u16] is required. You will have to initialize the slice or only pass pointers around.

6 Likes

It's currently undecided whether &mut [T] (or &mut T) require T to be valid/initialized or not, which is why MIRI doesn't error (for now). Do we have full recursive validity for references? · Issue #412 · rust-lang/unsafe-code-guidelines · GitHub

If it was decided that &mut [T] requires the T to be valid/initialized then there's no way to do this, because it would be UB by definition.

If it was instead decided that it is ok as long as you don't use the T then what you wrote seems ok to me as long as InsertStuffInBuffer never reads an instance of T (including trying to run its drop glue).

4 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.