正如您在上一篇文章的回答中提到的,基本上有三种方法可以得到 Stack Overflow 错误。
无限递归。这很容易确定 - 只需检查所有递归函数,它们是否正常工作并且在某些情况下总是会终止。
在堆栈上分配巨大的变量。这实际上与第一个问题有关 - 递归堆栈溢出发生,因为堆栈上没有空间用于另一个递归调用的局部变量。这也很容易确定 - 您必须使用许多(或很少,但很大)静态分配的数组(在编译时已知大小)或结构来导致问题。
缓冲区溢出。这是要追查的最糟糕的噩梦,因为实际问题可能在其原因发生很久之后才发生。
我建议尝试通过以下方式确定问题。
- 在问题仍然存在时,尽可能多地注释掉代码。如果幸运的话,您将注释掉实际上导致问题的地方。否则你将有更少的代码来分析。
- 使用 WinDbg(在平台 SDK 中提供)获取崩溃时的详细调用堆栈。您可以在系统注册表中添加以下条目,以强制操作系统将部分或全部进程内存转储收集到文件中,以便您可以尝试执行事后分析:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\YourAppName.exe]
"DumpFolder"=hex(2):63,00,3a,00,5c,00,44,00,75,00,6d,00,70,00,73,00,00,00
"DumpType"=dword:00000002
"DumpCount"=dword:0000000F
每次应用程序崩溃时,此更改都会将完整转储到 ac:\dumps 文件夹。
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\YourAppName.exe]
"DumpFolder"=hex(2):63,00,3a,00,5c,00,44,00,75,00,6d,00,70,00,73,00,00,00
"DumpType"=dword:00000001
"DumpCount"=dword:000000FF
每次应用程序崩溃时,此更改都会将小转储 (~40 Mb) 转储到 ac:\dumps 文件夹。
const char * sentry1 = "0123456789";
void * vitalField;
const char * sentry2 = "0123456789";
尤其是在类、结构和方法的开头和结尾处使用它们。使用调试模式确保优化器不会优化它们(因为未使用)。
崩溃后,收集内存转储并尝试检查,如果你所有的守卫都保持不变(这可能很困难,但并非不可能)。
- 最后,您可以进行非常详细的代码审查,以确保不会发生缓冲区溢出。
编辑:
您可以通过以下方式使 WinDbg 转储测试更加自动化:
_NT_SYMBOL_PATH=symsrv*symsrv.dll*c:\symbols*http://msdl.microsoft.com/download/symbols
它将被 WinDbg、Visual Studio 和 Process Explorer 使用
命令.txt
.sympath+.
.reload
kb
- 将以下条目添加到您的注册表中(检查您的系统是 32 位还是 64 位,并在必要时进行更改):
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT.dmp]
@="Debugger.Dump"
[HKEY_CLASSES_ROOT\Debugger.Dump]
[HKEY_CLASSES_ROOT\Debugger.Dump\Shell]
[HKEY_CLASSES_ROOT\Debugger.Dump\Shell\Debug_Without_Remote]
@="WinDbg This Dump"
[HKEY_CLASSES_ROOT\Debugger.Dump\Shell\Debug_Without_Remote\Command]
@="\"C:\Program Files\Debugging Tools for Windows (x64)\windbg\" -z \"%1\" -QY -c \"$<C:\Program Files\Debugging Tools for Windows (x64)\commands.txt\""
祝你好运 :)