方法的堆栈框架被删除但局部变量值仍然可访问?

时间:2015-07-23 18:52:28

标签: c pointers

我的理解是,只要调用testStack,就会创建一个新的堆栈帧,并且所有局部变量都将存在于该堆栈帧中。一旦堆栈帧被删除,那些局部变量也将消失。

在下面的程序中,我返回了testStack中创建的一个局部变量的内存位置,我能够在main方法中再次访问该变量值。

问题:

  1. 所以,这是真的,即使堆栈帧被删除但仍然存储器位置保持局部变量值或我误解了一些东西。
    • 即使删除了堆栈帧,也可以访问局部变量,这是否有潜在危险?
  2. testStack局部变量x是在堆栈上创建的,其值也在堆栈上。

    • 如果不是int x;我已经说过int* x;

      ,它在堆或堆栈内存方面是否有任何改变?
      string testStack();
      
      int main(void){
      string memAdd = testStack();
      printf("memAdd = %i\n", memAdd);
      printf("*memAdd = %i\n", *memAdd);
      printf("*&memAdd = %i\n", *&memAdd);
      *&memAdd = 11;
      printf("*&memAdd = %i\n", *&memAdd);
          }
      
      string testStack(){
          int x;
          printf("%i\n", x);
          printf("%i %p %p\n", x, x, &x);
          *&x = 33;
          printf("%i\n", x);
          //free(x);
          return &x;
      }
      
  3. O / P:

    134513341
    134513341 0x80482bd 0xbffd9eac
    33
    memAdd = -1073897812
    *memAdd = 33   //From main method... Stack frame of testStack() should have been removed by now...
    *&memAdd = -1073897812
    *&memAdd = 11
    

2 个答案:

答案 0 :(得分:2)

其他人或多或少地回答了你的问题。这里有一些更详细的信息:

1.“我的理解是,一旦调用了testStack,就会创建一个新的堆栈帧,并且所有局部变量都将存在于该堆栈帧中”

无法保证将创建堆栈帧。编译器可能决定传递寄存器中的所有参数,并可能将所有本地存储在寄存器中。这可能发生在有大量寄存器和本地人很少的功能的CPU上。

  1. “它会有什么不同......?”
  2. 一个。就堆而言:标准术语是堆不是代码或堆栈(而不是为全局变量保留的空间),您可以通过malloc()从中分配。堆栈通常以与堆相反的方向生长,因此当您在堆栈上推送某些内容时,剩余的堆空间会更少。如果一个参数在寄存器中传递,并且locals也在寄存器中,那么该片段将使用更少的堆栈/堆空间..我们不需要存储这些变量。

    湾int x vs int * x:x只是一个局部变量,我想不出任何情况,当它的类型会有所不同时(除了int的大小(以位为单位)与大小不同的例外情况一个不错的编译器可能适合这样的架构,也许是ARM的拇指模式?)。因此,如果编译器决定(可能是函数很小,频繁调用,可内联),本地将保存在寄存器中,那么就不会创建堆栈帧。

答案 1 :(得分:1)

x86平台上,通过增加esp寄存器并从堆栈恢复ebp寄存器来移除小屋框架。在下一个程序调用之前,不会触及堆栈内存,您可以访问它。但是其他平台可以以不同方式处理这些事情,因此从已删除的堆栈帧访问内存是未定义的行为。

修改 1)如果使用指针而会有什么不同吗?嗯,这取决于。如果您在堆上分配数据(使用例如new运算符),然后从您的过程返回指针 - 这是完全有效的技术。否则它几乎一样。

2)它可能有潜在危险吗?嗯,你必须澄清我们实际上在这里说的那种危险。这是有效的编程方法吗?当然不是。这是UB。这是潜在的安全漏洞吗?是的,也许吧。您不能指望编译器可以保证堆栈帧内存清理,您必须使用特殊方法自行完成。