2

通常のページ ヒープ (いっぱいではない) を使用して (分離されたテスト アプリで) クラッシュ シナリオをテストしようとしています。

フラグを設定しました

gflags /p /enable Test.exe

そして、整数バッファを1つの要素で上書きしています

...
const size_t s = 100;
vector<int> v1(s, 0);
int* v1_base = &v1[0];
write_to_memory_int(v1_base, s+1);
...

実際、ブロックがベクトル d'tor で解放されると、休憩が取れます。ブレークのコールスタックは正しく報告されます:

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

実際にはそれ以上の記録はないようです。

有用なスタック トレースを記録するようにページ ヒープを修正するにはどうすればよいですか?

Test プロジェクトはFPO (/Oy) でコンパイルされていないRtlAllocateHeapことに注意してください。FPO の影響を受けるとは予想していませんでした。


更新:手動で割り当てにステップインして、問題の呼び出しの FPO 性を確認しました (以下を参照) 。VC80(VS2005) ランタイム ライブラリmallocと同様に、何らかの形式の FPO が有効になっているように見えます。op newおそらく、ページ ヒープのスタック DB のスタック トレースが台無しになっている可能性があります。

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])

4

1 に答える 1

2

実際の割り当てスタック トレースを確認する必要があることをコメントで指摘してくれた @Marc Sherman に感謝します。

既に質問に編集されているように、スタック トレースに見られるように、CRT で FPO が有効になっているため、ここでは VC80(VS2005) が問題です。

MSVCR80!malloc+0x7a (FPO: [1,0,0]) (CONV: cdecl) 
MFC80U!operator new+0x2f (FPO: [Uses EBP] [1,0,0]) (CONV: cdecl)

検索するアンカーがあると、次のことがわかります。

UMDH のすべてのヒープ トレースが "malloc" で停止するのはなぜですか?

いくつかの引用符を追加します:

特に、Visual C++ 2005 の静的リンク CRT の既定の malloc 実装は、フレーム ポインターを使用しないだけでなく、ebp をスクラッチ レジスタとして破棄するように見えます ...

これはどういう意味ですか?まあ、Visual C++ 2005 でビルドされた malloc を使用するものは、少なくとも x86 ビルドでは、UMDH や ebp ベースのスタック トレースに依存するものでは診断できません。

素敵な情報を得たコメントにも返信があります:

Mark Roberts [MSFT] のコメント: 2008 年 2 月 25 日午後 3 時 3 分

こんにちは、

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

于 2013-09-27T13:56:07.577 に答える