debugging Visual Studio -如何查找堆损坏错误的来源

aiqt4smr  于 2023-04-21  发布在  其他
关注(0)|答案(9)|浏览(148)

我想知道是否有一个好的方法来找到导致堆损坏错误的源代码,给定在Visual Studio中分配的堆块“外部”写入的数据的内存地址;
专用(0008)空闲列表元素26 F7 F670大小错误(无效)
(试着写下一些关于如何查找内存错误的笔记)

pxiryf3j

pxiryf3j1#

开始安装windbg:
http://www.microsoft.com/whdc/Devtools/Debugging/default.mspx
然后像这样打开pageheap:

gflags.exe /p /enable yourexecutable.exe /full

这将在每次堆分配后插入一个不可写页。
在从windbg内部启动可执行文件之后,任何堆外的写入都会被这个调试器捕获。要在之后打开页面堆,请使用以下命令:

gflags.exe /p /disable yourexecutable.exe

关于如何使用pageheap here的更多信息。

bz4sfanl

bz4sfanl2#

对于Windows 10,您可以启用PageHeap option in the GFlags Tool,此工具作为Debugging Tools for Windows的一部分包含在内。
GFlags中的Page Heap选项允许您选择标准堆验证或整页堆验证。请注意,整页堆验证为每次分配使用整页内存,因此可能会导致系统内存不足。
要在GFlags中启用页面堆,请执行以下操作:
·要启用标准页堆验证,标准版本将在每次堆分配结束时写入模式,然后在分配释放时检查模式。
要验证所有进程,请用途:

gflags /r +hpa
gflags /k +hpa

对于单一工艺用途:

gflags /p /enable ImageFileName

·若要为一个进程启用全页堆验证,此选项会在每次分配结束时放置一个不可访问的页,以便程序在尝试访问分配之外的内存时立即停止,由于内存消耗量很大,因此应仅在单个进程上使用此选项。

gflags /i ImageFileName +hpa
gflags /p /enable ImageFileName /full

上面的两个命令可以互换。

  • 注意:上面提到的所有页面堆设置都是存储在注册表中的系统范围设置(/k除外),并且在您更改它们之前一直有效。/k设置是为此会话设置的内核标志设置,当Windows关闭时将丢失 *

另一个有用的工具是Application Verifier,但这不是Windows调试工具的一部分,而是包含在Windows Software Development Kit (SDK)中。

7qhs6swi

7qhs6swi3#

也许你可以试试微软的Application Verifier。它曾经为我解决过一个类似的问题,通过对堆操作进行额外的检查。在我看来,损坏地址的随机性是因为堆可以“微妙地”损坏,问题不会出现,直到堆发生大的事情(比如大规模分配/释放)。

3ks5zfa0

3ks5zfa04#

您可以在写入内存地址时设置断点。调试器将向您显示写入该位置的代码,但您仍然需要找出哪些写入导致了问题。

83qze16e

83qze16e5#

现在可能已经太晚了,但是如果它用gcc编译并且可以在linux上运行,你可以使用valgrind来找到问题的根源(我不记得标志了,我只用过一次,非常成功)。

k3bvogb1

k3bvogb17#

我假设C++作为语言。
如果错误是可再现的,并且损坏的地址总是相同的,则可以在写入此地址时放置数据断点以停止程序。

gudnpqoy

gudnpqoy8#

确保您链接到的所有库都是在与您正在运行的应用程序相同的CLR版本中编译的-全部在Release中或全部在Debug中。

当你在Debug和Release中编译时,你实际上是在针对两个不同版本的C运行时库。这两个版本非常不同,它们使用不同的策略来分配内存,它们使用不同的堆。但最重要的是要知道它们彼此不兼容。
Release C运行时库按预期分配内存,而Debug将添加额外的信息,例如用于跟踪缓冲区溢出的保护块和调用分配函数的位置,反过来它分配的内存比Release多。
如果你将你的应用程序链接到一个混合的DLL,这些DLL是在发布和调试中构建的,你很可能最终试图删除一个CLR中的一个对象,而这个对象是在另一个CLR中创建的。这意味着你将试图释放比分配给对象的内存更多或更少的内存,这可能会破坏堆。
您应该生成应用程序,并附加到在相同配置(发布或调试)下生成的库。
这个问题尤其可能发生在使用不同编译器编译的模块中。
有一种方法可以变通,我会提到但不推荐。如果出于某种原因你仍然需要在不同的模式下构建,这个变通方案将允许从同一个共享堆中分配和释放所有内存。API GetProcessHeap将允许你在不同的模块中访问共享堆。通过使用HeapAlloc & HeapFree你可以在共享堆中分配和释放内存。注意:HeapAlloc和HeapFree应该替换应用程序中所有对malloc和free的调用。

kmpatx3s

kmpatx3s9#

它救了我的命,我正在调试X-Plane 12堆损坏,这花了我一个星期的时间没有进展。
gflags.exe位于C:\Program Files\Debugging Tools for Windows(x64)\gflags.exe
并且必须以管理员身份运行,然后GUI图像输入使用X-Plane.exe,不要使用X-Plane.exe的路径。
然后点击“启用页面堆”,最后应用。但是“启用页面堆”对你的情况来说太强了,因为它会消耗大量的内存
好的,然后你可以像往常一样启动X-Plane 12,但是你会发现X-Plane的启动时间比以前要长得多,这不是调试目的的情况

相关问题