How does the internal representation of `str` work?

โš“ Rust    ๐Ÿ“… 2026-07-14    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 2      

surdeus

I'm currently working on a lint for clippy that discourages you from giving pointers to Rust strs to extern "C" functions, since that generally leads to UB (Lint str-ptr-in-c-abi discourage str pointers in C ABI fns by fpdotmonkey ยท Pull Request #17401 ยท rust-lang/rust-clippy ยท GitHub). However, I was testing out what actually happens when you do this, and I got a curious result.

let fmt = std::ffi::CString::new("hello.as_ptr() as *const _ == %s\n".as_bytes()).unwrap();
let hello = "Hello!";
/// SAFETY: fmt is a null-terminated string and requires 1 stringy variadic arg
/// that arg is hello, which is a pointer to a Rust string, which WILL CAUSE UB
unsafe { libc::printf(fmt.as_ptr() as *const _, hello.as_ptr() as *const _) };

Now, my mental model of str is that it looks something like this,

struct str {
    len: usize,
    start: *mut char,
}

which would suggest that the above would print this,

hello.as_ptr() as *const _ == \x{6}Hello!{overread nonsense}

but what it actually shows is this,

"Hello!".as_ptr() as *const _ == Hello!{overread nonsense}

Even for longer strings where '\x{N}' would be a printing character, it doesn't do anything. So what's happening under the hood? I looked through the source code and I didn't find any definition for str, at least in core/str/mod.rs

16 posts - 6 participants

Read full topic

๐Ÿท๏ธ Rust_feed