Don't lie to the compiler


#1

Just thought I’d post this reminder that the null-pointer optimization exists and if you’re not careful (like I wasn’t) you can create some very confusing situations. I guess the lesson is not to lie to the compiler.

use std::{ptr, slice};

fn main() {
    // Should be fine because the pointer's never dereferenced because the
    // length is zero, or so you'd think.
    let slice: &[u8] = unsafe {
        slice::from_raw_parts(ptr::null(), 0)
    };

    // It's obviously okay!
    let obviously_okay: Result<_, ()> = Ok(slice);
    
    // Or not.
    println!("Is it okay? {:?}", obviously_okay.is_ok());

    // => Is it okay? false
}

#2

I did not expect that to kick in for Result<NonzeroType, ()>. That could really bite someone. Is this gotcha documented anywhere?


#3

The documentation for std::slice::from_raw_parts outright says.

p must be non-null, even for zero-length slices, because non-zero bits are required to distinguish between a zero-length slice within Some() from None. p can be a bogus non-dereferencable pointer, such as 0x1, for zero-length slices, though.


#4

I opened the thread expecting a flame war :fire::smiling_imp::fire: