如何诊断Windows上的堆损坏错误

How do I diagnose heap corruption errors on Windows?

本文关键字:损坏 错误 Windows 何诊断 诊断      更新时间:2023-10-16

我使用Windows 8.1 64位和Visual Studio 2013 Ultimate。我正在将一个程序从Linux移植到Windows,它使用c++, OpenGL和SDL。我在64位的Windows上通过cmake自定义编译了适当的库。当我在Visual Studio中运行程序时,IDE说有一个头部损坏。这并不奇怪,因为我正在使用指针来实例化对象,并且我正在使用原始指针,为了参数的缘故,我计划将其更改为智能指针。我稍后会做提升魔法。

在此期间,我用我的Linux电脑通过Valgrind来诊断任何内存泄漏,Valgrind没有报告任何严重的问题。然后我继续使用CppCheck,但那里也没有什么严重的问题。也许我在这里太宽容了,Windows实际上可能比Linux更严肃地对待不那么严肃的事情,这是一个惊喜,因为MSVC往往比GCC更宽容。

所以,这个程序可以在Linux上运行,而不能在Windows上运行。(太棒了!)Visual Studio到处抛出异常,这让我更加讨厌Windows。我开始在谷歌上寻找解决方案,并遇到了这个叫做gflags或page helper的东西,所以我安装了调试工具并试图启动gflags,但我不知道如何使用它!后来我发现你必须使用其他一些叫做adp的工具,然后给它附加gflags,所以当我启动adp时,它崩溃了。所以现在我不知道该怎么做,正处于放弃移植的边缘(这很有趣,因为许多人都在抱怨将程序从Windows移植到Linux是多么困难,而事实恰恰相反)。

所以,现在我呼吁这个社区的帮助:我如何调试/诊断堆损坏错误发生在Windows上,而不是在Linux上?我真的应该使用gflags吗?还是我应该在这个问题上使用我的直觉?

使用调试堆并在main()的最开始调用它。

_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF);

它会使程序慢很多,但是一旦发生损坏,它应该会崩溃。

详细信息请参阅本文:https://msdn.microsoft.com/en-us/library/974tc9t1.aspx#BKMK_Check_for_heap_integrity_and_memory_leaks

@Carlos的解决方案对于小问题来说是完美的。但对于大问题,由此导致的速度放缓有时是你无法忍受的。

在这种情况下,可以放置

ASSERT(_CrtCheckMemory()); 

在代码的某个地方,人们怀疑问题已经存在。该命令在(且仅在)插入堆的位置检查堆,而不是像_CRTDBG_CHECK_ALWAYS_DF那样在每次newdelete调用之后检查堆。与选项_CRTDBG_CHECK_ALWAYS_DF相比,这使执行时间保持合理。

通过使用二进制搜索的方法来放置断言,可以很快地找到有问题的代码行。


然而,有时_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF)和/或_CrtCheckMemory()无法检测到问题。然后使用gflags是另一种可能性,它能够显示堆损坏发生的位置。简而言之:

  • 启用页面堆(通常你需要admin的权限),例如:
    "C:Program Files (x86)Windows Kits10Debuggersx64gflags.exe" /p /enable <full_path_to_exe_to_debug.exe> /full 
    
    会有一个报告,exe_to_debug.exe的堆检查被激活了。
  • 在调试器中运行程序。越界访问会破坏堆,这会导致访问冲突,并且很容易在调试器中看到。
  • 在调试完成后禁用页面堆,例如:
    "C:Program Files (x86)Windows Kits10Debuggersx64gflags.exe" /p /disable <full_path_to_exe_to_debug.exe>
    
  • 具有激活堆检查的
  • 程序可以通过列表列出
    "C:Program Files (x86)Windows Kits10Debuggersx64gflags.exe" /p