Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?

C/C++本地代码调试

子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?


nanjingesc 2010-05-25, 12:34 下午

char * GetString(void)

{

   char p[]="hello,world";

   return p;

}

void main(void)

{

   char *str=NULL;

   str=GetString();
}

现在问题就是:子函数的p数组在栈内存里,通过寄存器AX把这个栈地址返回了。

c 语言子函数返回的时候会保持栈平衡,所用的手法就是mov sp,bp,

通过debug调试发现,在该语句执行前,堆栈里的数据"hello,world"还在,

执行该语句后,堆栈该处的数据就变化了,变得不再是"hello,world",

所以想问下:堆栈平衡,仅仅是移动了sp指针,为什么会把原来栈里的数据清掉了呢?

又或者说是谁去做这样的事情呢?编译器,操作系统,还是CPU本身的机制呢?

我在WINDOWS的CMD窗口,和软盘启动的DOS都试过,结果一样。

 

Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?


luobing 2010-05-25, 18:38 下午

试验了,确实如此。与调试器有关。试验这样的代码:

char * GetString(void)

{

   char p[]="hello,world";

   return p;

}

char static_ptr[20];

void main(void)

{

   char *str=NULL;

  int i;

  for(i=0;i<20;i++)static_ptr[ i ]=0;

   str=GetString();

  for(i=0;i<20;i++)static_ptr[ i ]=str[ i ];

  printf("%s\n",str);

 printf("%s\n",static_ptr);
}

即在执行完GetString后直接将str中的值取出放入内存中,而不是作为局部指针存在。结果str打印出不确定字符串,static_ptr打印了hello,world.我们知道,局部指针指向的内存值在函数结束后是不确定的。

在非debug中,当函数执行到mov sp,bp的时候,实际上不会发生nanjingesc所叙述的情况(以上的例子证明了)。之所以在debug的环境中发生,是因为执行这条指令的时候,调试器本身也用到了堆栈,影响了这部分数据。同样的道理,为什么str打印出不确定的字符串,是因为printf影响了栈中的内容。这种现象不管用哪种调试器(当然是软件调试器,如TD,debug32等)应该都会发生。这个例子在林锐的书《高质量C/C++编程》中有叙述,但是他的描述不大准确,因为他的说法也是通过调试来发现数据变了,并没有说明这之间到底是怎么变化的。

     我现在在想另外一个问题,如果使用JTAG来调试的话,会不会出现这样的问题。之前调试某款BIOS的时候遇到过,只要往sp中塞入一个值,如mov sp,200h(当然,我确定200h处是我自己规定的堆栈),200h处的数据立即就改变了,这个问题一直没有想明白,手上也没有类似的环境调试。张老师,看到的话能否帮助想想,谢谢^^

 

Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?


格蠹老雷 2010-05-25, 20:10 下午

呵呵,二位都想得很深入。

这里的一个关键问题是CPU在发生异常时会自动向栈里压入包括IP寄存器在内的当前位置信息(参见《软件调试》11.1.3 P278)。而在调试时,单步跟踪会触发异常,导致CPU向栈里压入信息。

对于保护模式,因为异常处理代码在内核模式,所以要切换到使用内核态的栈,因此用户态的栈一般不会受影响。对于实模式情况,不涉及栈的切换,CPU会直接使用当前的栈,因此就会看到CPU曾经使用的痕迹。

对于现在的例子,编译成32位程序和编译成16位,结果应该是有所差异的。

对于32位的情况,应该是不会变的,除非有用户代码会用到这个空间,对于本例,在GetString返回后,即使在有调试器的情况下,观察main函数的str变量,还是应该可以看到本来的内容的,直到再调用其它函数,再使用栈,这个内容便可能会被破坏了。

仔细看下,如果还有问题,可以把编译好的exe发到我信箱一份。

Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?


Forward 2010-12-22, 16:29 下午
我对楼主说的现象觉得很奇怪,我这里测试,字符串是没有变化的,如果楼主确定变化的话,是否可以在调用前打内存断点,观察下。

Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?


不及格的程序员-八神 2010-12-24, 14:43 下午
很明显,栈上的内存被回收或是被其它的数据占用了.
也就是说你的str中保存的很可能是野指针,指向谁已经不确定了.
不及格的程序员-八神

Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?


heye 2011-01-01, 12:32 下午
在计算机中,无论是删除内存还是删除硬盘文件,一般情况下,如果没有特殊要求,只是将该区域表记为可用就算释放了。由此,也就有所谓的数据恢复软件,即当你删除文件后,如果该区域没有被其他文件占用,那么就有可能被恢复。
因此你这个话题是个伪话题:根本没有什么机制来清,只有两个机制:一是改变sp指针,使得该区域重新可用;二是新的数据的进入改变了原来的数据。

Powered by Community Server Powered by CnForums.Net