Advanced Debugging
About AdvDbg Consult Train Services Products Tools Community Contact  
欢迎光临 高端调试 登录 | 注册 | FAQ
 
  ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
 
  格蠹调试套件(GDK)
  格蠹学院
  小朱书店
  老雷的微博
  《软件调试》
  《格蠹汇编》
  《软件调试(第二版)》
沪ICP备11027180号-1

C/C++本地代码调试

帖子发起人: nanjingesc   发起时间: 2010-05-25 12:34 下午   回复: 5

Print Search
帖子排序:    
   2010-05-25, 12:34 下午
nanjingesc 离线,最后访问时间: 2011/1/6 11:26:17 nanjingesc

发帖数前150位
注册: 2010-02-24
发 贴: 8
子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?
Reply Quote

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都试过,结果一样。

 


IP 地址: 已记录   报告
   2010-05-25, 18:38 下午
luobing4365 离线,最后访问时间: 2022/5/16 2:05:04 luobing

发帖数前50位
注册: 2009-10-06
发 贴: 19
Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?
Reply Quote

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

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处的数据立即就改变了,这个问题一直没有想明白,手上也没有类似的环境调试。张老师,看到的话能否帮助想想,谢谢^^

 


IP 地址: 已记录   报告
   2010-05-25, 20:10 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?
Reply Quote

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

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

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

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

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

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


IP 地址: 已记录   报告
   2010-12-22, 16:29 下午
wbdwbd04 离线,最后访问时间: 2011/6/7 7:59:42 Forward

发帖数前25位
注册: 2009-12-23
发 贴: 50
Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?
Reply Quote
我对楼主说的现象觉得很奇怪,我这里测试,字符串是没有变化的,如果楼主确定变化的话,是否可以在调用前打内存断点,观察下。
IP 地址: 已记录   报告
   2010-12-24, 14:43 下午
ioriwellings 离线,最后访问时间: 2011/1/4 2:56:38 不及格的程序员-八神

发帖数前50位
男
注册: 2009-11-11
发 贴: 22
Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?
Reply Quote
很明显,栈上的内存被回收或是被其它的数据占用了.
也就是说你的str中保存的很可能是野指针,指向谁已经不确定了.
不及格的程序员-八神
IP 地址: 已记录   报告
   2011-01-01, 12:32 下午
heye711225 离线,最后访问时间: 2011/1/1 3:44:39 heye

无等级
注册: 2011-01-01
发 贴: 1
Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?
Reply Quote
在计算机中,无论是删除内存还是删除硬盘文件,一般情况下,如果没有特殊要求,只是将该区域表记为可用就算释放了。由此,也就有所谓的数据恢复软件,即当你删除文件后,如果该区域没有被其他文件占用,那么就有可能被恢复。
因此你这个话题是个伪话题:根本没有什么机制来清,只有两个机制:一是改变sp指针,使得该区域重新可用;二是新的数据的进入改变了原来的数据。
IP 地址: 已记录   报告
高端调试 » 软件调试 » C/C++本地代码调试 » Re: 子函数里的局部变量,使用的是栈内存,子函数返回后,该栈内存被谁清掉了?

 
Legal Notice Privacy Statement Corporate Governance Corporate Governance
(C)2004-2020 ADVDBG.ORG All Rights Reserved.