Do not create double raw pointer with "&mut std::ptr::null_mut()"

#[allow(unused_variables)]
fn test_double_ref_raw(){
    let data = 9;
    let ref_data = &data;

    let raw_data = ref_data as *const i32;
    // let d_raw_data = &ref_data as *const *const i32; //error[E0606]: casting `&&i32` as `*const *const i32` is invalid
    let d_ref_data = &&data;
    // let d_raw_data = d_ref_data as *const *const i32; //error[E0606]: casting `&&i32` as `*const *const i32` is invalid
    // why “casting `&&i32` as `*const *const i32` is invalid”
    // [see](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)

    //error sample, never use it. the double raw pointer is point to a stack memary
    fn err_d_raw() -> *mut *mut i32{
        let t: *mut *mut i32 = &mut std::ptr::null_mut();
        t
    }

    fn ok1_d_raw() -> *mut *mut i32{
        let t = Box::new(std::ptr::null_mut());
        Box::into_raw(t)
    }
    fn ok2_d_raw() -> *mut *mut i32{
        let layout = std::alloc::Layout::new::<*mut *mut i32>();
        let t = unsafe { std::alloc::alloc(layout) } as *mut *mut i32;
        t
    }
    let d1 = err_d_raw();
    let d2 = ok1_d_raw();
    let d3 = ok2_d_raw();
    println!("err_d_raw d1: {:p}\nok1_d_raw d2: {:p}\nok2_d_raw d3: {:p}",d1,d2,d3);
}
fn main() {
    test_double_ref_raw();
}

(Playground)

Output:

err_d_raw d1: 0x7fff92973b88
ok1_d_raw d2: 0x56520fd25ad0
ok2_d_raw d3: 0x56520fd25af0

Errors:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.99s
     Running `target/debug/playground`

Is there a hidden question or is this supposed to start a discussion? I'm a bit confused about what you're trying to achieve. In general, non-static lifetimes are always bound to a stack frame. You can use the stack pointer, as long as you don't try to return it from the current function and use it, afterwards. The latter two examples are semantically the same and allocate space on the heap, which can live until the end of the program and requires explicit memory deallocation. You may return those pointers from the current function and use them, afterwards.

You meant to write

let layout = std::alloc::Layout::new::<*mut i32>();

This is only a pragmatic error, because a pointer to an i32 and a pointer to a pointer to an i32 have the same size and alignment, which is what Layout cares about, but it's confusing and should be fixed.

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.