Getting the raw pointer to a heap allocated string

I am doing some experimenting with rust and running into some issues. What I am trying to do is allocate a String struct on the heap (not just the buffer) and hold a reference to that even after the object has been leaked. Then deref that pointer back into the string. The point of this is I am looking at implementing a simple garbage collector for a project and I need to have something keep track of all the objects in the system even after nothing references them. So I would keep a array of pointers to all the objects and then do the normal mark and sweep pass.

However I cannot seem to find a way to get a raw pointer to the String without consuming the Box (which I don't want to do, because other code needs to use this Box). When I try the code below I get the error non-primitive cast: std::string::String as *mut std::string::String. I know this not-idiomatic rust (and very unsafe), but any help would be appreciated.

fn main() {
    let before = Box::new("foo".to_string());
    let ptr = *before as *mut _; // can't get raw pointer here

    println!("before = {}", *before); // Still want to access box value here

    Box::leak(before); // memory is leaked

    unsafe {
        let after: String = *ptr; // can still access the string because we have the address.
        println!("after = {}", after);
    }
}

You can create a raw pointer by casting from a reference, for example from &String to *const String, or from &mut String to *mut String.

You'll also find that you can't move out of a raw pointer without using a function like ptr::read. A complete working example is:

fn main() {
    let before = Box::new("foo".to_string());
    let ptr = &*before as *const String; // can't get raw pointer here

    println!("before = {}", *before); // Still want to access box value here

    Box::leak(before); // memory is leaked

    unsafe {
        let after: String = std::ptr::read(ptr); // can still access the string because we have the address.
        println!("after = {}", after);
    }
}
2 Likes

Also note that there's Box::into_raw() that performs the cast and the leakage in one step, which is probably what you want (playground):


fn main() {
    let heap_str = Box::new(String::new());
    let heap_ptr = Box::into_raw(heap_str);

    println!("Raw pointer: {:p}", heap_ptr);

    // when you want managed memory again:
    let box_again = unsafe { Box::from_raw(heap_ptr) };
}

2 Likes

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.