Search code examples
rustffilifetime

Why is the lifetime important for slice::from_raw_parts?


The docs for slice::from_raw_parts warn the programmer to annotate the slice with the correct lifetime. I assume that, given some lifetime 'a, I can perform this annotation with

let myslice: &'a mut [i32] = std::slice::from_raw_parts_mut(ptr, sz)

I also assume that

  • Since myslice is a reference, it has nothing to do with the allocation/deallocation of the underlying data pointed to by ptr. The lifetime annotation doesn't affect the memory management of the data.
  • There's nothing tricky about memory management for myslice itself (i.e. a struct containing a pointer and a size). It's just like any other struct or i32. If I put it in a Box, then the std::raw::slice struct will get deallocated when the Box dies. The data referred to by the slice will not get deallocated, of course. The lifetime doesn't affect the memory management for the slice.

Why is it important that I get the lifetime correct? Is use-after-free the only danger to fear when setting the slice lifetime?


Solution

  • Use-after-free is not the only danger. With the wrong lifetime, one can cause mutable aliasing. Let's take this (contrived) function as an example:

    fn duplicate_mut_slice<'a, T>(xs: &mut [T]) -> &'a mut [T] {
        let ptr = xs.as_mut_ptr(); // btw, this part is safe!
        unsafe { std::slice::from_raw_parts_mut(ptr, xs.len()) }
    }
    

    Because of how the lifetimes line up, calls like this will succeed:

    fn alias_first_element<T>(xs: &mut [T]) -> (&mut T, &mut T) {
        let a = duplicate_mut_slice(xs);
        let b = duplicate_mut_slice(xs);
        (&mut a[0], &mut b[0])
    }
    

    Note that in this second function's signature, the lifetimes are correct and use-after-free is not an (immediate) danger. But mutable aliasing is very insidious. Basically everything relies on the guaranteed absence of mutable aliasing to prevent problems like race conditions, iterator invalidation, logic errors and indeed use-after-free (of something managed by the T). You can cause almost any problem imaginable with mutable aliasing.