String from raw parts

Hi,
I'm playing around with pointers and unsafe and I don't understand why this code segfaults

Playground

If I uncomment std::mem::ManuallyDrop it works. The example for String::from_raw_parts also uses it, but I don't understand why it's needed? The docs are saying that the ownership of the src pointer is transferred to the string.

Can anybody please explain what's going on here?

Also, why does it takes a *mut pointer? Just a convention? I've noticed a lot of stdlib functions use *mut even for reading.

1 Like

A (normal) String is allocated and stored on the heap, but you're constructing one that points to static memory. At the end of the block the Strings Drop implementation (deconstructor) runs and attempts to deallocate the memory being pointed to. It was never allocated in the first place, thus the segfault.

Trying to modify or extend the contents of the constructed String would have similar results (modifying read only memory, or trying to realloc a non-allocated piece of memory).

2 Likes

Ah I see, I thought it copies the data to the string. Changing the string will only work if the pointer points to the heap, which is not true in my case. It all makes sense. Thank you!

If you want to go from str to String, call to_owned(), which will allocate the memory necessary for the String to contain the data of str.

Here’s how to (unsafely) copy a String from a *const u8 pointer. As you can see, no *mut pointer is is required. If you find any other places where you think the standard library “unnecessarily” requires *mut feel free to ask about it because it may very well be a misunderstanding of what the function in question actually does (i.e. it might actually be able to mutate the data behind the pointer).

fn main() {
    let src = "Hello";
    let s = unsafe {
        ptr_to_string(src.as_ptr(), 5)
    };
    println!("{}", s);
}

unsafe fn ptr_to_string(ptr: *const u8, len: usize) -> String {
    std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len)).to_owned()
}

(playground)

1 Like

I like this solution! Thank you.

BTW, the documentation of String::from_raw_parts() clearly states that one of the reason it is unsafe is that…: