pengowen123
pengowen123

Reputation: 1017

Prevent drop until pointer is dropped with no_std

I have a struct that stores a raw pointer to some data:

struct Foo<T> {
    x: *const T
}

impl<T> Foo<T> {
    fn new(x: &[T]) -> Foo<T> {
        Foo {
            x: &x[0] as *const T
        }
    }
}

The data is actually a slice, but I use the offset method to avoid directly storing the data. The constructor puts the a pointer to the data into the field, and returns the struct. However, if I try to return a Foo from a function:

fn foo() -> Foo<i32> {
    let x = [1, 2, 3];
    Foo::new(&x)
}

fn main() {
    unsafe {
        println!("{}", &*foo().x);
    }
}

The data is dropped too early, and the field x points to garbage. What I want to have happen is the data x points to is cloned, and the clone lives for as long as the struct does. How can I accomplish this?

Upvotes: 2

Views: 1012

Answers (1)

DK.
DK.

Reputation: 59095

You don't.

You're trying to escape a pointer to stack data, which is something Rust would forbid you from doing if you were using regular borrowed pointers. However, by using raw pointers and unsafe, you've effectively stripped off the various protections the compiler would normally enforce.

You really, really shouldn't be using unsafe unless you understand what's happening.

You also cannot extend the lifetime of something created within a function without moving it out. There is simply no way of passing out a pointer (or a borrow) of x.

The fix for this is to just not do it in the first place. Use borrowed pointers (&i32 or &[i32]) or owned values (i32, Vec<i32>).

Another possibility would be to allocate the necessary storage in the caller and pass a &mut into foo, which you can then slice, mutate, and return a borrowed sub-slice to. That, of course, requires that you can statically define an upper-bound on how much space foo will need, but such is life without std.

Upvotes: 4

Related Questions