返回指向局部变量的指针时的堆栈行为

Aka*_*all 1 stack rust

我有一个简单的例子,其中Rust的行为与我的心理图像不匹配,所以我想知道我错过了什么:

fn make_local_int_ptr() -> *const i32 {
    let a = 3;
    &a
}

fn main() {
    let my_ptr = make_local_int_ptr();
    println!("{}", unsafe { *my_ptr } );
}
Run Code Online (Sandbox Code Playgroud)

结果:

3
Run Code Online (Sandbox Code Playgroud)

这不是我所期望的.使用堆栈和堆中给出的符号

我希望堆栈框架看起来像这样:

Address | Name | Value
-----------------------
   0    |   a  |   3  
Run Code Online (Sandbox Code Playgroud)

在里面make_local_int_ptr(),但在此之后,

let my_ptr = make_local_int_ptr();
Run Code Online (Sandbox Code Playgroud)

由于a超出范围,我希望堆栈被清除.但它显然没有.

此外,如果我在创建my_ptr和打印它的解除引用值之间定义另一个变量:

fn main() {
    let my_ptr = make_local_int_ptr();
    let b = 6;
    println!("{}", b); // We have to use b otherwise Rust
                       // compiler ignores it (I think)
    println!("{}", unsafe { *my_ptr } );
}
Run Code Online (Sandbox Code Playgroud)

我的输出是:

6
0
Run Code Online (Sandbox Code Playgroud)

这也不是我的预期,我在想:

Address | Name | Value
-----------------------
   0    |   b  |   6
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我的输出将是:

6
6 
Run Code Online (Sandbox Code Playgroud)

甚至(在C++Go我得到这个结果):

Address | Name | Value
-----------------------
   1    |   b  |   6  
   0    |   a  |   3
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我的输出将是:

6
3
Run Code Online (Sandbox Code Playgroud)

但为什么我得到了我得到的输出?

另外,为什么甚至允许返回指向局部变量的指针?变量超出范围,指针指向的值变得不可预测.

DK.*_*DK. 7

您根本不应该返回指向本地堆栈变量的指针.这样做是未定义的行为,编译器可以完全自由地做任何想做的事情.

当你说unsafe,你承诺编译器,你将手动支持所有预期的不变量......然后立即打破这个承诺.

坦率地说:你违反了记忆安全,所有的赌注都没有了.解决方案是这样做.


然而,为了解释为什么你可能会看到这种行为(同样,这是未定义的行为,没有任何保证):在用零覆盖的意义上,堆栈不会被"清除"; 再也无法从中读取它.

此外,由于调用make_local_int_ptr已完成,编译器没有理由保留其堆栈空间,因此它可以重用任何空间.的0可能由于呼叫println!