1、拿到dump文件,输入命令~*kbn,发现异常出现在14号线程,下面是14号线程的调用栈。一般来说,对付“kernel32!UnhandledExceptionFilter+0x1af”的方法是输入命令“.cxr poi(0xXXXXXXXX+4)”,(其中0xXXXXXXXX为第一个参数,即红色标出位置的值)即可看到发生异常前的调用栈。但是在本实例中这个值为0x00000000,是个无效地址,我们已经不能用常规方法看到调用栈了
2、恢复调用栈,输入dds esp L1000,查看调用栈,下面是其中的一些关键部分。通过查找ebp便可以恢复调用栈了(从0fadff94 向上找到0fadff88再向上找到0fadd724,依次类推) 而最后的0fadd674再也找不到存储它的地方了,说明这里已经是调用栈的尽头。那么破坏栈的地方也就是发生在这里了VFPrintOpr!CVFPrintMgrWnd::Refresh+0x25 [E:\Daily_Build\code\src\Set_Nuclear\EngStationFunctions\VFPrintMgr\VFPrintMgrWnd.cpp @ 165]通过进一步分析代码查看变量值便可以找到问题的所在
3、栈的结构,栈是从高地址开始压栈的. 如下图,函数中存在函数调用,首先是Frame1压栈,然后是Frame2压栈.其调用关系是Frame1调用Frame2. 对于参数的压栈windows默认的stdcall,cdell都是从右边参数开始压栈.而delph所试用的passcall是从左开始压栈. 因此,加入存在一个函数fun(int p1, int p2); 其压栈如下图
4、我们如何来判断函数的栈指针,参数地址和局部变量地址呢? 举一个简单的windbg的kv命令输出:ChildEBP RetAddr Args to Child 03b1f9c4 0032549e 00e1b5f0 00e259f8 7c900059 如上所示,ebp是栈的指针,其中ebp+4保存的是函数返回地址,因此ebp+8(00e1b5f0 )开始就是函数的参数. 结合上面的栈地址图,由于栈是从高到低压栈,所以不可能往高位扩展(那样会破坏上层堆栈),因此局部变量只能是向低位扩展,所以通常ebp-4就是低一个局部变量地址. 由于是在往低位扩展,所以当局部变量过多或者函数层数过多时,会出现堆栈溢出
5、常见的相关问题A、栈溢出:一个线程的内核栈只有12K大小,耗尽了就会溢出,所以开发人员须注意尽量不要在栈上分配超过1K的内存,不能递替调用,但是如果调用太深的话,还是会溢出的。那么如何判断堆栈溢出呢? windbg有一个非常有用的命令kf -n ,其中n是要显示的frame数. 举例
6、下图是一个栈破坏图,其中p1,p2,local1, local2是属于Frame2的下层函数. 其形势是,当栈的局部变量没有破坏,上层函数的局部变量都没有破坏. 考虑破坏通常是连续性的,比组越界,那破坏源可能是来自三个方面:前栈的局部变量越界,比如Local 1是个数组,越界访问后,破坏参数;不过这个几率确实为局部变量是向低位扩展,要破坏高位,要么是用了负索引数组,要么是程序指定去操作前栈的参数引起的破坏,比如对p1地址进行越界访问;层栈在调用前就破坏栈,这种通常是上层的局部变量的越界访问,且参数是引用时出现,