Visual Studioで割り当てられたヒープブロックの「外部」に書き込まれたデータのメモリアドレスを考えると、ヒープ破損エラーを引き起こすソースコードを見つける良い方法があるのだろうか。
専用(0008)フリーリスト要素26F7F670のサイズが間違っています(デッド)
(メモリエラーを見つける方法に関するメモを書き留めようとしています)
前もって感謝します!
Windbgのインストールから始めます。
http://www.Microsoft.com/whdc/Devtools/Debugging/default.mspx
次に、次のようにページヒープをオンにします。
gflags.exe –p /enable yourexecutable.exe /full
これにより、各ヒープ割り当ての後に書き込み不可のページが挿入されます。
この後、windbg内から実行可能ファイルを起動すると、ヒープ外の書き込みがこのデバッガーによってキャッチされます。後でページヒープをオフにするには、これを使用します:
gflags.exe -p /disable yourexecutable.exe
Pageheapの使用方法に関する詳細情報 here 。
Window 10では、GFlagsツールの PageHeapオプションを有効にすることができます 、このツールは Debugging Tools for Windows の一部として含まれています。
GFlagsのページヒープオプションでは、標準のヒープ検証またはフルページヒープ検証を選択できます。完全なヒープ検証では、割り当てごとにメモリの全ページが使用されるため、システムメモリが不足する可能性があることに注意してください。
GFlagsでページヒープを有効にするには:
標準ページヒープ検証を有効にするには、標準バージョンが各ヒープ割り当ての最後にパターンを書き込み、割り当てが解放されたときにパターンを調べます。
すべてのプロセスを確認するには:
gflags/r + hpa
gflags/k + hpa
単一プロセスで使用する場合:
gflags/p/enable ImageFileName
1つのプロセスで全ページヒープ検証を有効にするには、このオプションは各割り当ての最後にアクセスできないページを配置し、割り当てを超えてメモリにアクセスしようとするとプログラムが直ちに停止するようにします。大量のメモリ消費のため、単一プロセスで。
gflags/i ImageFileName + hpa
gflags/p/enable ImageFileName/full
上記の2つのコマンドは交換可能です。
注:上記のすべてのページヒープ設定は、レジストリに保存されているシステム全体の設定(/ kを除く)であり、変更するまで有効です。/k設定は、このセッション用に設定されたカーネルフラグ設定であり、Windowsのシャットダウン時に失われます
もう1つの便利なツールは Application Verifier ですが、これはWindows用デバッグツールの一部ではなく、 Windows Software Development Kit( SDK) 。
MicrosoftのApplication Verifierを試すことができます。ヒープ操作の追加チェックをオンにすることで、同様の問題を一度解決しました。私の意見では、破損したアドレスのランダム性は、ヒープが「微妙に」損傷する可能性があり、ヒープに大きな何かが発生するまで問題が発生しないためです(大量の割り当て/空きなど)。
メモリアドレスへの書き込みにブレークポイントを設定できます。デバッガーはその場所に書き込むコードを表示しますが、どの書き込みが問題を引き起こしているのかを解決する必要があります。
おそらく遅すぎるかもしれませんが、gccでコンパイルしてLinuxで実行できる場合は、valgrindを使用して問題の原因を見つけることができます(フラグを覚えていないので、一度だけ使用して大成功を収めました)。
gflagsおよびPageHeapの詳細(これは非常に役立ちました): http://msdn.Microsoft.com/en-us/library/windows/hardware/ff549561%28v=vs.85%29.aspx =
言語としてC++を想定しています。
エラーが再現可能であり、破損したアドレスが常に同じである場合、このアドレスに書き込むときにデータブレークポイントを設定してプログラムを停止できます。
リンク先のすべてのライブラリが、実行中のアプリケーションと同じCLRバージョンでコンパイルされていることを確認します-すべてがリリースで、すべてがデバッグで。
デバッグとリリースのいずれかでコンパイルする場合、実際には2つの異なるバージョンのCランタイムライブラリをターゲットにしています。これらのバージョンはまったく異なり、メモリを割り当てるためのさまざまな戦略を使用し、さまざまなヒープを使用します。しかし、知っておくべき最も重要なことは、それらが互いに互換性がないことです。
リリースCランタイムライブラリは期待どおりにメモリを割り当てましたが、デバッグはバッファオーバーフローを追跡するガードブロックや割り当て関数を呼び出した場所などの追加情報を追加し、リリースよりも多くのメモリを割り当てます。
リリースとデバッグで作成されたDLLの組み合わせにアプリケーションをリンクしている場合、別のCLRで作成された1つのCLRのオブジェクトを削除しようとする可能性が高くなります。これは、オブジェクトに割り当てられたメモリよりも多かれ少なかれメモリを解放しようとしているため、ヒープが破損する可能性があることを意味します。
アプリケーションをビルドし、リリースまたはデバッグの同じ構成でビルドされたライブラリにアタッチする必要があります。
この問題は、特に異なるコンパイラでコンパイルされているモジュールで発生する可能性があります。
回避する方法がありますが、これについては言及しますが、推奨しません。何らかの理由で別のモードでビルドする必要がある場合、この回避策により、すべてのメモリを同じ共有ヒープから割り当てて解放することができます。 API GetProcessHeapを使用すると、さまざまなモジュール全体で共有ヒープにアクセスできます。 HeapAllocとHeapFreeを使用すると、共有ヒープ内のメモリを割り当てたり解放したりできます。注:HeapAllocおよびHeapFreeは、アプリケーション内のmallocおよびfreeのすべての呼び出しを置き換える必要があります。