ヒープの破損を特定するために PageHeap を使用しています。アプリケーションのヒープが破損しています。ただし、メソッドに渡された文字列の stl オブジェクトを作成すると、アプリケーションが (クラッシュにより) 中断します。クラッシュ場所の近くに目に見えるメモリの問題は見られません。ヒープの破損を検出するためにフル ページ ヒープを有効にし、スタックの破損を検出するために /RTC を有効にしました。
ヒープの破損が発生した正確な場所でブレークするにはどうすればよいですか?
ヒープの破損を特定するために PageHeap を使用しています。アプリケーションのヒープが破損しています。ただし、メソッドに渡された文字列の stl オブジェクトを作成すると、アプリケーションが (クラッシュにより) 中断します。クラッシュ場所の近くに目に見えるメモリの問題は見られません。ヒープの破損を検出するためにフル ページ ヒープを有効にし、スタックの破損を検出するために /RTC を有効にしました。
ヒープの破損が発生した正確な場所でブレークするにはどうすればよいですか?
FULL ページヒープを有効にすると、デバッガーがヒープの破損をキャッチする可能性が高くなります。
gflags /p /enable /full <processname>
また、どのアドレスが上書きされているかがわかれば、windbg でメモリアクセスにブレークポイントを設定できます。VS デバッガーに同じ機能があるかどうかはわかりません。
ページヒープは、ヒープの破損が発生した瞬間に正確に検出するとは限りません。
ページヒープは、割り当ての直後に無効なページを挿入します。したがって、割り当てられたブロックをオーバーランするたびに、AV が発生します。しかし、他にも考えられるケースがあります。1 つの例は、ヒープ ブロック ヘッダー データ構造を破壊する割り当てられたブロックの直前に書き込むことです。ヒープ ブロック ヘッダーは有効な書き込み可能なメモリです (ほとんどの場合、割り当てられたブロックと同じページにあります)。次の例を検討してください。
#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と比較してパフォーマンスの低下がはるかに少ないため、より複雑なシナリオを実行できます。