7

Windowsでは(特にMFCを使用して)泥沼だと感じたため、何年もの間、新しいオペレーターで何かをしようとすることを避けてきました。言うまでもなく、グローバル(またはクラス)のnewやdeleteをいじる非常に説得力のある理由がない限り、そうすべきではありません。

しかし、私には厄介な小さなメモリ破損のバグがあり、それを追跡したいと思います。以前に解放されたメモリが上書きされたことを示すメッセージがCRTデバッグアロケータから届きます。このメッセージは、ブロックを再利用しようとした後の割り当て呼び出し中にのみ表示されます(とにかく、これがどのように機能するかを信じています)。

問題のコードの一部が原因で、エラーメッセージと破損のポイントは非常に無関係です。私が知っているのは、「以前は1つのヌルバイトで解放されていたメモリをどこかで上書きした」ということだけです。(これは、デバッガーを使用し、デバッグヒープによって参照されるメモリをいくつかの異なる実行で監視することで確認しました)。

犯人がどこにいるのかという明らかな考えを使い果たしたので、私はもっと厳密なことをしようとすることになりました。解放された各ブロックをメモリのアクセス不可ページにして、ライターがCPUのMMCにすぐに捕らえられるようにすると、理想的だと思いました。後で少し検索すると、それらの線に沿って何かを実装した人を見つけました。

http://www.codeproject.com/Articles/38340/Immediate-memory-corruption-detection

彼のコードは大量の再発明コードに埋もれていますが、コアコンセプトの抽出は非常に簡単で、私はそうしました。

私が今抱えている問題は、MFCがnewをDEBUG_NEWとして再定義し、さらに多数のデバッグインターフェイスをCRTまで定義することです。さらに、グローバル演算子newおよびdeleteを定義します。したがって、C ++に関する限り、「ユーザー」はグローバル演算子newを置き換えて2回削除しようとしているため、「シンボルはすでに定義されています」という効果に対するリンカーエラーが発生します。

インターネットとSOを見てみると、いくつかの有望な記事がありますが、MFCのグローバル演算子のnew/deleteを置き換えることについて最終的に肯定的なことは何もありません。

グローバルなnewおよびdelete演算子を適切に置き換える方法
MFCアプリケーションのデバッグビルドでメモリアロケータを置き換えることは可能ですか?

私はすでに知っています:

  • MFC / CRTは、メモリ割り当て用の豊富なデバッグツールをすでに提供しています。

まあ、それはそれが提供するものを提供します-そもそも私がこの道を転がり落ちたメッセージなど。私は今、腐敗が起こっていることを知っていますが、それはひどく弱いソースです!

私が提供したいのは、保護された割り当て(または単に保護された割り当て解除)です。これは、多くの仮想アドレススペースを使用し、すべての割り当てを分離して配置することで明らかに可能になります。これは、メモリを大幅に浪費します。さて、ええ、これが今のような特別な目的の瞬間に役立つデバッグ専用コードである場合、欠点はわかりません。

だから、私は必死に次の解決策を探しています

  1. CRT / MFCが提供しているにもかかわらず、コンパイラを強制的にグローバル演算子new/deleteと一致させます。
  2. MFC / CRT _heap_alloc_dbgチェーンをフックして、最後から2番目の割り当てのために自分のコードの代わりに自分のコードを使用する別の方法を見つけます(つまり、OSのVirtualAlloc / VirtualFreeを介して割り当て、新しいメモリや新しいメモリを供給します。 malloc)。

誰かが答え、またはこれらがどのように達成されるかについていくらかの光を当てるかもしれない読むべき良い記事を知っていますか?

その他のアイデア:

  1. サンク技術を使用して、実行時にCRTの新規/削除を置き換えます。
  2. 他のアプローチは完全に?!

さらなる調査:

  • この記事はかなりクールです...実行時にグローバルな新規/削除演算子にパッチを適用する方法を提供します。ただし、記事が指摘しているように、これは少しハックです(ただし、これはデバッグビルドにのみ必要なので、大したことではありません)http://zeuxcg.blogspot.com/2009/03/fighting-against-crt- heap-and-winning.html
    • したがって、これは私が望むもの(CRTメモリ割り当て関数を置き換えるメカニズム)に到達していますが、この実装はかなり時代遅れであり、これまでのところ、それを機能させる試みは無数の問題にぶつかっています。もともと作成されたバージョンにハッキングされすぎて、比較的単純なコンソールの使用(つまり、C、C ++でさえなく、Microsoft CRTによって提供されるほとんどのデバッグ機能を放棄する)のためだけだと思います。したがって、非常にクールなアイデアですが、現在のVS2010開発スタジオで作業を行うには最終的に何時間もの労力がかかるため、(私にとっては)価値がありません。
  • どうやらこのアイデアのよく知られたバージョンがあります:http://en.wikipedia.org/wiki/Electric_Fence残念ながら私が見つけたWindowsポートでさえhttp://code.google.com/p/electric-fence-win32 / CRTを適切にオーバーライドできませんが、すべてのソースコードを変更して、電気柵のヒープ割り当てコードにアクセスするように求められます。:(

2012年5月3日更新:

  • そして今、Windowsがすでに電気柵の実装を提供していることを発見しました。GFLAGSデバッグツールhttp://support.microsoft.com/kb/286470を介してアクセスでき ます。これは、テスト対象のアプリケーションの外部でオンとオフを切り替えることができます。これは基本的に私が興味を持っていたものと同じテクノロジーであり、DUMAプロジェクト(電気柵のブランチ-http://duma.sourceforge.net/)の機能を備えています
4

1 に答える 1

4

MSVCRTデバッグヒープは実際にはかなり優れており、n番目の割り当てのブレークポイントなど、使用できるいくつかの便利な機能があります。

http://msdn.microsoft.com/en-us/library/974tc9t1(v=VS.80).aspx

特に、この種の問題をデバッグするために使用できるデバッグ情報などを出力する割り当てフックを挿入できます。

http://msdn.microsoft.com/en-us/library/z2zscsc2(v=vs.80).aspx

あなたの場合、あなたが本当にする必要があるのは、各割り当てのアドレス、ファイル、および行を出力することだけです。次に、破損したブロックが発生した場合は、その直前のアドレスを持つブロックを見つけます。これは、ほぼ確実にオーバーランしたブロックです。Visual Studioデバッガーのメモリビューを使用して、破損したメモリアドレスを確認し、前のブロックを確認できます。それはあなたがそれがいつ割り当てられたかを知るためにあなたが知る必要があるすべてをあなたに伝えるべきです。

デバッグヒープには、割り当てられた各ブロックに数値の割り当てIDもあり、n番目に中断する可能性があります。割り当て。したがって、適度に一貫した再現を取得でき、同じ数値ブロックが毎回破損する場合は、「n番目のブレーク」機能を使用して、割り当てられた時間の完全な呼び出しスタックを取得できるはずです。

_CrtCheckMemoryまた、破損がはるかに早く発生したかどうかを確認するのに役立つ場合があります。定期的に呼び出すだけで、バグを括弧で囲んだら(一方のエラーは発生せず、もう一方のエラーも発生しました)、それらをどんどん近づけていきます。

于 2012-05-02T16:11:26.690 に答える