我正在尝试使用普通页面堆(未完整)测试崩溃场景(在一个独立的测试应用程序中)。
我已经用
设置了标志gflags /p /enable Test.exe
我正在用一个元素覆盖一个整数缓冲区
...
const size_t s = 100;
vector<int> v1(s, 0);
int* v1_base = &v1[0];
write_to_memory_int(v1_base, s+1);
...
实际上,当这个块在向量中被释放时,我得到了休息。正确报告了中断的callstack:
0:005> kp
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr
0785faa4 11229df2 verifier!VerifierStopMessage+0x1f8
0785fb08 1122a22a verifier!AVrfpDphReportCorruptedBlock+0x1c2
0785fb64 1122a742 verifier!AVrfpDphCheckNormalHeapBlock+0x11a
0785fb84 112290d3 verifier!AVrfpDphNormalHeapFree+0x22
0785fba8 77951564 verifier!AVrfDebugPageHeapFree+0xe3
0785fbf0 7790ac29 ntdll!RtlDebugFreeHeap+0x2f
0785fce4 778b34a2 ntdll!RtlpFreeHeap+0x5d
0785fd04 750c14dd ntdll!RtlFreeHeap+0x142
0785fd18 71fc4c39 kernel32!HeapFree+0x14
0785fd64 00404b0a msvcr80!free(void * pBlock = 0x0726f7b8)+0xcd [f:\dd\vctools\crt_bld\self_x86\crt\src\free.c @ 110]
0785fd90 00402ac7 Test!std::vector<int,std::allocator<int> >::_Tidy
...
但是,当我查看错误分配时,我只能得到这个:
0:005> !heap -p -a 0x0726f7b8
address 0726f7b8 found in
_HEAP @ 30000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0726f790 0039 0000 [00] 0726f7b8 00190 - (busy)
1122a6a7 verifier!AVrfpDphNormalHeapAllocate+0x000000d7
11228f6e verifier!AVrfDebugPageHeapAllocate+0x0000030e
77950d96 ntdll!RtlDebugAllocateHeap+0x00000030
7790af0d ntdll!RtlpAllocateHeap+0x000000c4
778b3cfe ntdll!RtlAllocateHeap+0x0000023a
也就是说, 是一个分配堆栈跟踪,但它停在RtlAllocateHeap
,这显然是完全没用的。
查看内存中的堆栈跟踪:
dt _DPH_BLOCK_INFORMATION ....-0x20
=>
0:005> dds 0x03e556f4
03e556f4 00000000
03e556f8 00002050
03e556fc 00050000
03e55700 1122a6a7 verifier!AVrfpDphNormalHeapAllocate+0xd7
03e55704 11228f6e verifier!AVrfDebugPageHeapAllocate+0x30e
03e55708 77950d96 ntdll!RtlDebugAllocateHeap+0x30
03e5570c 7790af0d ntdll!RtlpAllocateHeap+0xc4
03e55710 778b3cfe ntdll!RtlAllocateHeap+0x23a
03e55714 00000000
03e55718 00003001
03e5571c 0004005e
事实上似乎没有更多的记录。
如何修复页面堆以记录有用的堆栈跟踪?
请注意,使用FPO(/ Oy)编译的测试项目不,我不希望FPO影响RtlAllocateHeap
吗?
更新:我通过手动进入分配来检查有问题的呼叫的FPO-ness(见下文),看起来VC80的两个malloc
和op new
(VS2005) )运行时库已经启用了某种形式的FPO ...所以也许这会弄乱页堆的堆栈数据库的堆栈跟踪。
0:004> kv
ChildEBP RetAddr Args to Child
077efa7c 77c8af0d 05290000 01001002 00000190 ntdll!RtlDebugAllocateHeap+0x16 (FPO: [Non-Fpo])
077efb60 77c33cfe 00000190 00000000 00000000 ntdll!RtlpAllocateHeap+0xc4 (FPO: [Non-Fpo])
077efbe4 72344d83 05290000 01001002 00000190 ntdll!RtlAllocateHeap+0x23a (FPO: [Non-Fpo])
077efc04 62f595ee 00000190 00000000 00000000 MSVCR80!malloc+0x7a (FPO: [1,0,0]) (CONV: cdecl)
077efc1c 00406a44 00000190 ebecf74f 00000001 MFC80U!operator new+0x2f (FPO: [Uses EBP] [1,0,0]) (CONV: cdecl)
077efc48 00405479 00000064 00000000 3fffffff Test!std::_Allocate<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > >+0x84 (FPO: [Non-Fpo]) (CONV: cdecl)
077efcb8 004049f4 00000064 ebecf68f 00000000 Test!std::vector<unsigned int,std::allocator<unsigned int> >::_Buy+0x69 (FPO: [Non-Fpo]) (CONV: thiscall)
077efd88 00402a4f 00000064 077efdc0 ebecf44b Test!std::vector<int,std::allocator<int> >::_Construct_n+0x44 (FPO: [Non-Fpo]) (CONV: thiscall)
077eff4c 72342848 00000000 ebec8474 00000000 Test!crashFN+0x35f (FPO: [Non-Fpo]) (CONV: cdecl)
077eff84 723428c8 75da33aa 072ab3d8 077effd4 MSVCR80!_callthreadstart+0x1b (FPO: [Non-Fpo]) (CONV: cdecl)
077eff88 75da33aa 072ab3d8 077effd4 77c39f72 MSVCR80!_threadstart+0x5a (FPO: [1,0,0]) (CONV: stdcall)
077eff94 77c39f72 072ab3d8 70fca8b2 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
077effd4 77c39f45 7234286e 072ab3d8 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
077effec 00000000 7234286e 072ab3d8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
答案 0 :(得分:2)
感谢@Marc Sherman在评论中指出我应该检查实际的分配堆栈跟踪。
正如已经编辑过的问题,VC80(VS2005)就是这里的问题,因为它的CRT启用了FPO,如堆栈跟踪中所示:
MSVCR80!malloc+0x7a (FPO: [1,0,0]) (CONV: cdecl)
MFC80U!operator new+0x2f (FPO: [Uses EBP] [1,0,0]) (CONV: cdecl)
现在,有了搜索锚点,我们发现以下内容:
Why does every heap trace in UMDH get stuck at “malloc”?
添加一些引号:
特别是,它似乎是默认的malloc实现 在Visual C ++ 2005上的静态链接CRT上不仅不使用框架 指针,但它将ebp作为临时寄存器...
这一切意味着什么?好吧,使用构建的malloc的任何东西 Visual C ++ 2005无法使用UMDH或其他任何内容进行诊断 依赖于基于ebp的堆栈跟踪,至少不依赖于x86版本。
评论中也有回复,其中有很好的信息:
Mark Roberts [MSFT]说:2008年2月25日下午3:03
您好,
为8.0 CRT启用FPO并不是故意的。 Visual Studio 2008 CRT(9.0)没有启用FPO,UMDH应该运行 通常
对于8.0,UMDH的替代方案是使用LeakDiag。 LeakDiag 实际上将检测内存分配器以获取堆栈跟踪。 这使它比UMDH更通用,因为它可以挂钩几个 不同粒度的不同分配器类型(范围从 c运行时到原始虚拟内存分配)。
默认情况下,LeakDiag只是遍历堆栈基指针,但它可以 被修改为使用Dbghlp StackWalkAPI来解析FPO数据。这个 虽然性能损失较高,但会产生完整的堆栈。上 另一方面,你可以自定义堆栈行走行为 到一定的深度等,以尽量减少性能损失。
请在此处找到LeakDiag: ftp://ftp.microsoft.com/PSS/Tools/Developer%20Support%20Tools/LeakDiag/leakdiag125.msi