Example about: i32 ref and i32 owned in fns

// E1:
//..
pub fn _new(v  :&i32)->Self{
    let ptr: *const i32 = v; // ref argument
    Self(v,ptr)
}
//...
//E2:
///..
pub fn _new(v :i32)->Self{
    let ptr: *const i32 = &v;  // owned argument
    Self(v,ptr)
}
//...

E1:Compiler Explorer
E2:Compiler Explorer

Question: In fn (self),Is

fn(self)->*const Self{ &self as *const i32} == fn(&self)->*const Self{ self as *const i32} 

?

E2 is UB because the pointer is only valid for the stack frame where v lives.

That's right. :grinning_face_with_smiling_eyes: . It's modify from E1 so I have forgot remove a comment.

They are very different.

self is a local variable that always becomes invalid by the end of the function. In the first function, the *const i32 is pointing at that local variable, and so it is pointing at garbage after the function completes. It's a dangling pointer, and it is always invalid to dereference it at the call site.

In the second function, self is a reference to something that exists outside of the function. And the *const i32 is pointing at that same thing which is outside of the function. You never create a reference or pointer to the self variable in this case, you just effectively return a copy of one that already exists. How long the returned pointer is valid to dereference depends on what is going on at the call site.


struct Length(i32,*const i32);

pub fn from_ptr(&self) -> i32{
    // SAFE: Length drop then i32 drop too!!
    unsafe{self.1.read()}
}

When you move the Length around, the address where the i32 is changes, but the value of the *const i32 does not change, so this doesn't work like you seem to think it does.

There's a problem with the unsafe block in E1. The lifetime of v: &i32 in _new is unrestricted, so its address may or may not be valid at the time of from_ptr.

Here's an exploit of the unsafety. You can run it with Miri by selecting it in the "TOOLS" dropdown.

Apart from changing the code to use a reference, I can think of 2 ways to fix this: (I consider myself a beginner, feel free to correct me!)

By the way, if you meant to create a self-referencing struct (i.e. the pointer points to an address inside Length, which I guess you want to be its i32 field) then I read that it requires using Pin to prevent the Length from being moved. I'm not really familiar with that, but I'll drop a link to the docs

And your current code is not self-referencing, E1's pointer points to wherever v points to (can be in main's stack frame, on the heap via &*b where b is a Box<i32>, etc), and E2's pointer points within _new's stack frame allocation.

you are right!! I have through v in fn _new(v:&i32) doesn't move but it was wrong. ( and move 0x8)

thank for corrected me.

asm at reference case: (asm wasn't optimised !!!!)

// no optimise  
mov   dword ptr [rsp + 64], 20
lea     rdi, [rsp + 64]  //then call new()
///Box
mov     rax, qword ptr [rsp + 40]
move    dword ptr [rax], 20
 mov     qword ptr [rsp + 152], rax
 mov     rax, qword ptr [rsp + 152]
 mov     qword ptr [rsp + 24], rax // then call new

It works differently.
simple ref is save value in stack and suply ref to it.
but box is different. it reserve ptr. change value under this ptr. after all it save the ptr to another stack.
and if it was deref it will take the value under this ptr. and save it in another stack.

so in ref case it would fixed the addr
but in the box ptr case the address can be change if it was allocated and deref_ed .

Could you tell some tool can help me read a asm more automatically ? I know IDA . but I don't understand it well

Are you looking for --emit=asm?