我正在使用 PageHeap 来识别堆损坏。我的应用程序有堆损坏。但是当应用程序为传递给方法的字符串创建 stl 对象时,应用程序会中断(由于崩溃)。我在崩溃位置附近看不到任何可见的内存问题。我启用了整页堆来检测堆损坏和 /RTCs 来检测堆栈损坏。
我应该怎么做才能在发生堆损坏的确切位置中断?
我正在使用 PageHeap 来识别堆损坏。我的应用程序有堆损坏。但是当应用程序为传递给方法的字符串创建 stl 对象时,应用程序会中断(由于崩溃)。我在崩溃位置附近看不到任何可见的内存问题。我启用了整页堆来检测堆损坏和 /RTCs 来检测堆栈损坏。
我应该怎么做才能在发生堆损坏的确切位置中断?
启用 FULL pageheap 可以增加调试器在发生堆损坏时捕获它的机会:
gflags /p /enable /full <processname>
此外,如果您能找出被覆盖的地址,您可以在 windbg 中设置内存访问断点。不确定 VS 调试器是否具有相同的功能。
Pageheap并不总是在发生堆损坏的那一刻准确地检测到它。
Pageheap在分配后立即插入无效页面。因此,每当您超出分配的块时,您都会得到一个 AV。但还有其他可能的情况。一个例子是在分配的块破坏堆块头数据结构之前写入。堆块头是一个有效的可写内存(很可能与分配的块在同一页中)。考虑以下示例:
#include <stdlib.h>
int
main()
{
void* block = malloc(100);
int* intPtr = (int*)block;
*(intPtr-1) = 0x12345; // no crash
free(block); // crash
return 0;
}
所以在分配的块通过之前写一些垃圾就可以了。启用Pageheap 后,该示例中断了内部free()
调用。这是调用堆栈:
verifier.dll!_VerifierStopMessage@40() + 0x206 bytes
verifier.dll!_AVrfpDphReportCorruptedBlock@16() + 0x239 bytes
verifier.dll!_AVrfpDphCheckNormalHeapBlock@16() + 0x11a bytes
verifier.dll!_AVrfpDphNormalHeapFree@16() + 0x22 bytes
verifier.dll!_AVrfDebugPageHeapFree@12() + 0xe3 bytes
ntdll.dll!_RtlDebugFreeHeap@12() + 0x2f bytes
ntdll.dll!@RtlpFreeHeap@16() + 0x36919 bytes
ntdll.dll!_RtlFreeHeap@12() + 0x722 bytes
heapripper.exe!free(void * pBlock=0x0603bf98) Line 110 C
> heapripper.exe!main() Line 11 + 0x9 bytes C++
heapripper.exe!__tmainCRTStartup() Line 266 + 0x12 bytes C
kernel32.dll!@BaseThreadInitThunk@12() + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
Pageheap支持严格的堆一致性检查,但在调用其他一些堆 API 之前,检查不会启动。检查例程在堆栈上可见。(如果没有Pageheap,应用程序可能只是在堆实现中尝试使用无效指针的 AV。)
因此,Pageheap并不能 100% 保证在损坏发生的那一刻准确捕捉到损坏。您需要像Purify或Valgrind这样的工具来跟踪每个内存访问。
别误会,我觉得Pageheap还是很有用的。与提到的Purify和Valgrind相比,它导致的性能下降要少得多,因此它允许运行更复杂的场景。