1
votes

So I understand the simple answer to how this works is that local stuff happens in the stack and box stuff happens on the heap.

However, what happens when you have more complex behavior?

Specifically, lets talk about data that gets held in FFI for an indeterminate amount of time and then has to be resurrected later from a *mut c_void.

If you 'forget' a pointer, using std::mem::forget, or std::mem::transmute() a pointer to a *const pointer how durable is the result?

If (for example) this is done inside a function and then the function returns, does the stack get cleared and the memory become invalid?

Are 'Box' pointers which are heap allocated generally speaking valid until they get destroyed (eg. using read())?

I've been told on IRC that this is generally speaking the correct approach to take:

unsafe fn fp(v:Box<Foo>) -> *const c_void {
  return transmute(foo);
}

However, looking at libcore::raw::Box, Box isn't remotely the same as a *const T; is that really ok?

1

1 Answers

4
votes

If you 'forget' a pointer, using std::mem::forget, or std::mem::transmute() a pointer to a *const pointer how durable is the result?

If you cast a Box with transmute via the fp function, the pointer will remain valid as long as you like, since transmute is consuming the value and thus the destructor, which frees the memory, does not run. (At least, it is valid until you transmute it back to Box<...> to let the destructor run and free the memory.)

forget has no return value, it just discards the value without running the destructors.

Note, however, transmuting to *const c_void requires extra care, e.g. the Foo inside the Box<Foo> may contain thread-local data, or references, and thus may not be valid to pass between threads, or live forever. (Meaning the pointer itself lives forever/is usable however you like, but the data it points to may not.)

If you start casting & pointers, you need to be very very careful about lifetimes and not letting them escape from the scope of the data to which they point (e.g. you can't return a pointer to a local variable from a function).

If (for example) this is done inside a function and then the function returns, does the stack get cleared and the memory become invalid?

The stack doesn't get 'cleared' (i.e. it's not explicitly zeroed), but it is invalid to use any pointers into a stack frame that doesn't exist any more.

Are 'Box' pointers which are heap allocated generally speaking valid until they get destroyed (eg. using read())?

You'll need to be more specific, ptr::read cannot be called on a Box directly, and calling ptr::read on a *const c_void certainly won't do anything useful.

However, looking at libcore::raw::Box, Box isn't remotely the same as a *const T; is that really ok?

raw::Box is not at all the representation of the normal Box. raw::Box is the representation of the old @ (now Gc) type. Box<T> is literally a wrapper around a *mut T.