我目前正在尝试在我们的代码库中追踪堆损坏的来源,当打开完整页堆跟踪时这不会出现(因此只有正常的页面跟踪)。
我正在使用Application Verifier打破损坏,并获得一个不太有用的停止代码00000008:
APPLICATION_VERIFIER_HEAPS_CORRUPTED_HEAP_BLOCK(8)
堆积损坏。
如果堆块中的损坏不能放在更具体的类别中,则会发出这种一般性错误。=======================================
VERIFIER STOP 00000008:pid 0xD30:堆块损坏。00000000:呼叫中使用的堆句柄 0861C000:操作中涉及的堆块。
0000043C:堆块的大小。
00000000:保留=======================================
我不得不削减报告以保护无辜者,但要忍受我。 callstack显示:
1000c540 00000008 00000000 vrfcore!VerifierStopMessageEx+0x543
00000008 7c969624 00000000 vrfcore!VfCoreRedirectedStopMessage+0x81
00000000 00000009 0861c000 ntdll!RtlpDphReportCorruptedBlock+0x101
04a680ee 01001002 03ce1000 ntdll!RtlpDphTrimDelayedFreeQueue+0x84
03ce1000 01001002 04a680ee ntdll!RtlpDphNormalHeapFree+0xc0
03ce0000 01001002 137a0040 ntdll!RtlpDebugPageHeapFree+0x79
03ce0000 01001002 137a0040 ntdll!RtlDebugFreeHeap+0x2c
03ce0000 01001002 137a0040 ntdll!RtlFreeHeapSlowly+0x37
03ce0000 00000000 137a0040 ntdll!RtlFreeHeap+0xf9
137a0040 137a0040 030dfe61 msvcrt!free+0xc3
现在最初,我把注意力集中在对free()
的调用上,假设我试图释放的内存是堆损坏的罪魁祸首。情况可能仍然如此,但我不再相信。在我逐步执行删除调用时看着0x137a0040
,通过调用RtlpDphNormalHeapFree()
可以正确释放内存。我总结说它被正确释放,因为从0x137a0040
到它的上限约76mb后面的内存仅由f0
组成,将here定义为free'd memory。
因此,在致电RtlpDphReportCorruptedBlock()
,RtlpDphTrimDelayedFreeQueue()
之前,我的注意力转向了通话。传递给RtlpDphReportCorruptedBlock()
的参数将向我表明(只是一个猜测,我找不到关于这些函数的声明的任何提示)成为腐败的块。调查此块显示以下内容:
0861c000 f0 f0 f0 f0 4f f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 ....O..............
为什么这是第5个字节4f
,而所有其他字符都是f0
(已经被释放)? RtlpDphTrimDelayedFreeQueue()
做了什么?问题(如果这是问题)是这个函数试图释放显然已经释放的内存,或者此函数是否期望此内存已经空闲,并且在遇到第5个字节时正在丢失情节?
(第5个字节是唯一的奇数,0x0861c000
到0x0861c43c
是f0
)
不幸的是,虽然我可以在100%的时间内重现堆损坏,但每次在其上放置数据断点时,地址似乎都会发生变化。
我在Windows XP SP3上运行,应用程序是用VC ++ 6编写的
有什么想法吗?
答案 0 :(得分:1)
C或C ++?
如果是C ++,也许你可以覆盖新的&删除并自己找到它。从来没有真正释放内存,而是放入你的银行。在内存中使用毒药前后分配内存,并在内存中存放毒药,并一直检查毒药。
如果是C,你可以用#define malloc做类似的事情。我还会搜索VC6是否允许你输入你的处理程序而不是malloc和free。
答案 1 :(得分:1)
这表明你在释放它之后修改了块 - 可能来自不同的线程,或者因为某些东西仍然有一个指向它的指针。 (当你释放它时,运行时将它设置为所有F0,保持一段时间,然后检查它仍然是所有F0;它不是,所以它必须在空闲后被修改。)
如果损坏与块的常量偏移,您可以在调用free()
的位置更改该位置的断点。
答案 2 :(得分:0)
看起来您正在处理堆损坏,并且几乎可以肯定,在您发布的调用堆栈实际崩溃之前的某个时间发生了损坏。 Rtl...()
函数不会导致损坏,它们只是强制检测它。
This MSDN message描述了与您类似的问题以及一些调试它的方法。还有this MS-KB article描述了VC6中的堆损坏。这些链接(以及我发现的其他几个链接)都提到了多线程,可以检查是否使用它。
MS也有PageHeap应用程序,尽管它可能与Application Verifier做同样的事情。