How do I specify the lifetime of a slice made from slice::from_raw_parts()?

Hello,

Does anybody know how I would go about tying the lifetime of a slice I get back from slice::from_raw_parts() in the code below with the lifetime of some other variable of my choice, such as x?.

This would be really useful with the windows crate since I sometimes get back pointers that I would like to turn into something the compiler can help make sure I don't misuse later on.

fn main() {
    some_fn();
}

fn some_fn<'a>() {
    let  slice;
    {
        let x:&'a i32 = &42; 

        {
            let ptr = x as *const _;
            
            // want to somehow tie the lifetime of this slice to the same lifetime as x manually
            slice = unsafe { core::slice::from_raw_parts::<'a, _>(ptr, 1) };
        }
        
        // Want this to be allowed since the lifetime of x is still valid here
        assert_eq!(slice[0], 42); 
    }
    // Would like this to result in compile error since lifetime of x is not valid here
    println!("{:?}", slice);    
}

In short, I would like that last println! to give me a compile time error since I'm using slice without initializing it.

One thing that comes to mind is using generic type/lifetime inference (Playground):

fn slice_tied_to<'a, T, U>(_: &'a T, ptr: *const U, len: usize) -> &'a [U] {
    unsafe {
        core::slice::from_raw_parts(ptr, len)
    }
}

and then use it like

let x = 42;
let slice = slice_tied_to(&x, &x, 1);
3 Likes

Generally the way to do this is to define a helper function and put the lifetime relationship on the function signature.

2 Likes

Is there no way to do it inline with the rest of the code without calling out to some helper function?

I'm wary of using a helper function here because if you tie the lifetime of the slice to something that doesn't live long enough, that's undefined behaviour.

Since Rust guarantees that you should never be able to cause undefined behaviour from safe code, this helper function must be marked unsafe. This means whoever is using it must understand the internals of the function and guarantee they can uphold the assumptions.

Since that's the case, I would rather not have a tiny one line unsafe helper function if it is possible to just do it inline with the rest of the code.

Is this at all possible to do?

You could use a scoped API:

unsafe
fn with_slice_from_raw_parts<T, R> (
    ptr: *const T,
    len: usize,
    scope: impl FnOnce(&[T]) -> R,
) -> R
{
    scope(::core::slice::from_raw_parts(ptr, len))
}

so as to:

unsafe {
    let ptr = x as *const _;
    slice = with_slice_from_raw_parts(ptr, 1, |slice| {
        assert_eq!(slice[0], 42);
        slice // Error, invalid lifetimes
    });
    // thus `slice` is not valid here,
}
// thus not valid here either:
println!("{:?}", slice); // Error

But @H2CO3 and @alice's suggestions are the more common out there. @H2CO3's can sometimes be declined into a raw ptr part, and a "lifetime handle" part:

unsafe
fn slice_from_raw_parts<'scope, T : 'scope> (
    ptr: *const T,
    len: usize,
    _: &'scope (),
) -> &'scope [T]
{
    ::core::slice::from_raw_parts(ptr, len)
}

so as to:

{
    let ptr = x as *const _;
    let scope = ();
    slice = unsafe { slice_from_raw_parts(ptr, 1, &scope) };
}

println!("{:?}", slice); // Error, `scope` was dropped.

There is nifty one which is a variant of @H2CO3's suggestion, which is to use the pointer itself as a scope. It can be too "clever"/terse for its own good but it's nice once you get acquainted with it:

unsafe
fn slice_from_raw_parts<'scope, T> (
    &ptr: &'scope *const T,
    len: usize,
) -> &'scope [T]

from there:

slice_from_raw_parts(&ptr, 1) // can't go beyond `ptr`'s own local lifetime!
2 Likes

I'm not sure I understand how the first example works.

But it seems like there's no getting around defining a helper function for manipulating lifetimes. I'll keep that in mind. Many thanks.

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.