rustmemory

I need help understanding &'static in rust(unsafe)


I want to understand how from_pointer will behave. What does that &'static mean? Will the lifetime of the &'static T outlive the scope? It's unsafe anyway. The lifetime is set by the value that is given to to_pointer. I just wanna know how it would behave if I would create a ton of references to the same item.

if I have something like this:

 let pointer = to_pointer(&string);
 for _ in 0..999999 {
     let value = from_pointer(pointer);
     println!("{value}")
 }

will it cause a memory leak? is value disposed at the closing bracket or will this create a ton of refrences that are never disposed?

fn to_pointer<T>(value: &T) -> *const T {
    value as *const T
}

fn from_pointer<T>(pointer: *const T) -> &'static T {
    unsafe { &*pointer }
}

Same goes for this. What effect does the T: 'static have. can it cause memory leaks? My guess would be that it is the same as from_pointer

pub struct Pointer<T>(*const T);
impl<T: 'static> Deref for Pointer<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        unsafe { &*self.0 }
    }
}

Solution

  • Gosh. There's a lot to unpack here.

    What does that &'static mean? Will the lifetime of the &'static T outlive the scope?

    A reference with 'static lifetime indicates that the referent lives for the remaining lifetime of the running program. That raw pointers do not carry a lifetime that the compiler can use to perform borrow-checking, and you are therefore capable of creating &'static references from them, does not mean that doing so is correct or valid: it is up to you to ensure that the preconditions (in this case that the pointer will be valid for reads for the remaining lifetime of the running program) are satisfied.

    will it cause a memory leak?

    I think you are using the term "memory leak" incorrectly. A memory leak occurs when allocated memory is no longer reachable, but is not freed (this isn't usually desirable, as it is a waste of resources, but it is perfectly defined and acceptable behaviour in Rust). I think you may have instead meant to ask about "dangling pointers" which are almost the exact opposite: pointers to freed memory. It is Undefined Behaviour to have a reference to freed memory.

    is value disposed at the closing bracket or will this create a ton of references that are never disposed?

    value is indeed dropped when to_pointer returns; however, value in this case is just a reference to T. Dropping a reference does not drop the referent, so the T will still be in its memory location after to_pointer returns.

    However, because your from_pointer creates an &'static T while the pointer is not guaranteed to remain valid for 'static lifetime, it is not correct. A better version might look like this:

    /// # Safety
    /// `pointer` must be valid for shared reads for the `'a` lifetime
    unsafe fn from_pointer<'a, T>(pointer: *const T) -> &'a T {
        &*pointer
    }
    

    This way, calling from_pointer is an unsafe operation, and callers are required to uphold the safety precondition.

    What effect does the T: 'static have

    T: 'static constrains which types may instantiate the generic parameter to those that have only 'static borrows (or longer, which doesn't exist). It does not guarantee that the pointer is valid, and therefore the implementation of Deref is incorrect unless you are able to guarantee that a Pointer<T> can only exist when its field is valid to read for shared access. Otherwise, a better version might look like this:

    impl<T> Pointer<T> {
        /// # Safety
        /// The pointer must be valid for shared reads for the `'a` lifetime
        unsafe deref<'a>(&self) -> &'a T {
            &*self.0
        }
    }
    

    This way and as before, responsibility for upholding the safety precondition is pushed onto the caller.