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

Visual studio Visual Studio-如何查找堆损坏错误的源,visual-studio,debugging,heap-memory,Visual Studio,Debugging,Heap Memory,我想知道是否有一种很好的方法可以找到导致堆损坏错误的源代码,因为数据的内存地址是在VisualStudio中分配的堆块“外部”写入的 专用(0008)自由列表元素26F7F670大小错误(无效) (尝试写下一些关于如何查找内存错误的注释)您可以在写入内存地址时设置断点。调试器将向您显示写入位置的代码,但您仍然需要计算哪些写入会导致问题。 < P>我假定C++为语言。< /P> 如果错误是可复制的,且损坏的地址始终相同,则在该地址写入时,可以设置数据断点以停止程序。也许您可以尝试Microsoft

我想知道是否有一种很好的方法可以找到导致堆损坏错误的源代码,因为数据的内存地址是在VisualStudio中分配的堆块“外部”写入的

专用(0008)自由列表元素26F7F670大小错误(无效)


(尝试写下一些关于如何查找内存错误的注释)

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

< P>我假定C++为语言。< /P>
如果错误是可复制的,且损坏的地址始终相同,则在该地址写入时,可以设置数据断点以停止程序。

也许您可以尝试Microsoft的应用程序验证程序。 它曾经为我解决了一个类似的问题,通过打开堆操作的额外检查。
在我看来,地址损坏的随机性是因为堆可能会被“微妙地”损坏,而这个问题在堆发生重大变化(如大规模分配/空闲)之前不会出现。

从安装windbg开始:

然后像这样打开页面堆:

gflags.exe –p /enable yourexecutable.exe /full
这将在每次堆分配后插入一个不可写页面

在此启动windbg内部的可执行文件后,堆外的任何写入现在都将被此调试器捕获。要在以后打开页面堆,请使用以下命令:

gflags.exe -p /disable yourexecutable.exe

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

可能太晚了,但是如果它使用gcc编译并且可以在linux上运行,您可以使用valgrind查找问题的根源(我不记得标志,我只使用了一次,取得了巨大的成功)。

关于Gflags和pageheap的更多信息(帮助很大):

对于窗口10,您可以启用,此工具作为的一部分提供

GFlags中的页面堆选项允许您选择标准堆验证或完整页面堆验证。注意,完整堆验证对每个分配使用一整页内存,因此可能会导致系统内存不足

要在GFlags中启用页面堆,请执行以下操作:

•要启用标准页面堆验证,标准版本将在每个堆分配结束时写入一个模式,然后在释放分配时检查该模式

要验证所有流程,请使用:

gflags/r+hpa

gflags/k+hpa

对于单个流程使用:

gflags/p/enable ImageFileName

•若要为一个进程启用整页堆验证,此选项会在每次分配结束时放置一个不可访问的页,以便程序在试图访问超出分配的内存时立即停止,由于内存消耗过大,此选项只应在单个进程上使用

gflags/i ImageFileName+hpa

gflags/p/enable ImageFileName/full

上述两个命令可以互换

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


另一个有用的工具是,但这不是Windows调试工具的一部分,而是包含在中

确保链接到的所有库与正在运行的应用程序在同一CLR版本中编译-全部在发行版中或全部在调试中。

当您在Debug和Release中编译时,实际上是针对两个不同版本的C运行时库。这些版本非常不同,它们使用不同的策略来分配内存,并且使用不同的堆。但最重要的是要知道它们彼此不兼容

Release C运行时库按预期分配内存,而调试将添加额外的信息,如跟踪缓冲区溢出的保护块和调用分配函数的位置,并反过来分配比Release更多的内存

如果要将应用程序链接到在Release和Debug中构建的DLL组合,则很可能最终会尝试删除在一个CLR中创建的另一个CLR中的对象。这意味着您将尝试释放比分配给对象的内存更多或更少的内存,这可能会损坏堆

您应该构建您的应用程序,并附加到在相同配置下构建的库(发布或调试)

此问题尤其可能发生在使用不同编译器编译的模块中


有一种解决方法,我会提到,但不推荐。如果出于某种原因,您仍然需要在不同的模式下进行构建,此解决方案将允许从同一共享堆中分配和释放所有内存。API GetProcessHeap将允许您在不同的模块中访问共享堆。通过使用HeapAlloc&HeapFree,您可以在共享堆中分配和释放内存。注意:HeapAlloc和HeapFree应该替换应用程序中对malloc和free的所有调用。

语言是C/C++混合语言。损坏的地址在每个调试会话中都是不同的,所以我想不可能使用数据断点。不幸的是,您是对的。在这些情况下,我的方法是#将free/delete定义为nothing。如果问题消失,我将malloc/new/free/delete定义为记录每次调用的函数,以便查找重复的删除或不分配的删除。最佳解决方案!救了我的命。此外,直接打开gflags.exe并使用GUI也可以工作。转到“图像文件”,填写exe文件名,并选中“启用页面堆”。任何调试器都可以工作。非常感谢。我花了两天时间才找到你