1

Cコードアプリが1つあります。MS-VS2005を使用して構築していました。mallocを使用して動的に割り当てられていた1つの出力データバッファーがありました。

一部のテストケースでは、mallocされていたメモリサイズが、生成された実際の出力サイズ(バイト単位)よりも不足していました。その大きいサイズの出力が小さいサイズのバッファに書き込まれ、バッファオーバーフローが発生しました。その結果、テスト実行がクラッシュし、MSVS-2005に「ヒープの破損...」というウィンドウが表示されました。

動的メモリ割り当てに関係していることはわかっていましたが、出力に必要な十分なサイズを割り当てていたため、メモリ割り当てを疑うことなく、実際に根本的な原因を見つけるのに長い時間がかかりました。しかし、ある特定のテストケースでは、私が計算したよりも多くの出力が生成されたため、クラッシュが発生しました。

私の質問は:

1.)このような動的メモリバッファのオーバーフロー状態を検出するために使用できるツール。また、バッファオーバーフロー状態の検出にも役立ちますか(バッファ/アレイがヒープ、スタック、グローバルメモリ領域にあるかどうかに関係なく)?

2.)メモリリークツール(Purifyなど)またはlint、klocworksなどのコード分析ツールは特定の場合に役立ちますか?ランタイム分析ツールでなければならないと思います。

ありがとうございました。

-広告。

4

4 に答える 4

1

試すことができるのは、VirtualAllocを使用して十分なページ+1を割り当て、PAGE_READONLYでVirtualProtectを使用することです。最後のページでPAGE_GUARDフラグを立ててから、疑わしい割り当てを調整して、オブジェクトの終わりが保護されたページの始まりに近づくようにします。すべてがうまくいけば、ガードページにアクセスしたときにアクセス違反が発生するはずです。どの割り当てが上書きされるかをおおよそ知っていると役立ちます。それ以外の場合は、すべての割り当てをオーバーライドする必要があり、多くの追加メモリが必要になる場合があります(割り当てごとに少なくとも2ページ)。私がここで「統計ページガード」と名付けているこの手法のバリエーションは、小さなオブジェクトの大きな肥大化を回避するために、その方法で割り当ての比較的小さな割合にのみランダムにメモリを割り当てることです。多数の実行を実行すると、エラーが発生する可能性があります。この場合、乱数ジェネレーターは時間のようなものからシードオフする必要があります。同様に、下位アドレスで上書きが疑われる場合は、オブジェクトの前にガードページを割り当てることができます(両方を同時に行うことはできませんが、ランダムに混同する可能性もあります)。

更新:gflags.exe(以前はpageheap.exeでした)マイクロソフトユーティリティはすでに「統計ページガード」をサポートしているので、私は車輪の再発明をしました:)あなたがする必要があるのはgflags.exe / p /enable[/を実行することだけですランダム0-100]YourApplication.exeを実行し、アプリを実行します。ヒープ割り当てにカスタムヒープまたはカスタムガードを使用している場合は、少なくともバグをキャッチするためにHeapAllocの使用に切り替えてから、元に戻すことができます。Gflags.exeはサポートツールパッケージの一部であり、Microsoftダウンロードセンターからダウンロードできます。そこで検索してください。

于 2009-12-15T00:27:18.670 に答える
1

『 Writing Solid Code 』という本で最初に出会った解決策の1つは、 malloc()APIを診断コードで「ラップ」することです。

最初に、診断malloc()は後続の番兵に追加のバイトを割り当てるように調整します。たとえば、割り当てられたメモリに続く追加の4バイトは予約されており、文字「FINE」が含まれています。

後で、からのポインタmalloc()がに渡されるfree()と、対応する診断バージョンのfree()が呼び出されます。メモリの標準実装を呼び出してfree()放棄する前に、末尾の番兵が検証されます。変更しないでください。番兵が変更された場合、診断から返された後のある時点でブロックポインタが誤用されていますmalloc()

バッファオーバーフローを検出するためにセンチネルパターンではなく、メモリ保護ガードページを使用することには利点があります。特に、パターンベースの方法では、不正なメモリアクセスは事後にのみ検出されます。センチネルパターン方式では、不正な書き込みのみが検出されます。メモリ保護方式は、不正な読み取りと書き込みの両方をキャッチし、発生するとすぐに検出されます。

の診断ラッパー関数は、同じメモリブロックに対する複数の呼び出しなど、malloc()のその他の誤用にも対処できます。また、の呼び出し元をテストするために、デバッグ環境で実行されたときに常にブロックを移動するように変更できます。malloc()free()realloc()realloc()

特に、診断ラッパーは、割り当てられて解放されたすべてのブロックを記録し、プログラムの終了時にメモリリークを報告する場合があります。メモリリークは、プログラムの実行中に解放されないことによって割り当てられるブロックです。

malloc()APIをラップするときは、とを含むすべての関連関数をラップする必要がcalloc(), realloc(),ありstrdup()ます。

これらの関数をラップする一般的な方法は、プリプロセッサマクロを使用することです。

#define malloc(s)diagnostic_malloc(s、__FILE__、__LINE__)
/*など....*/

標準実装への呼び出しをコーディングする必要が生じた場合(たとえば、割り当てられたブロックは、標準free()実装を使用してブロックを解放することを期待するサードパーティのバイナリのみのライブラリに渡され、元の関数名にアクセスできます。 --を使用してプリプロセッサマクロではなく(malloc)(s)、関数名を括弧で囲みます。

于 2009-12-28T22:26:42.767 に答える
0

PC-Lintは、malloc / new sizeの問題のいくつかの形式をキャッチできますが、それがあなたの問題を見つけたかどうかはわかりません。

VS2005には、デバッグモード(関数の最後で実行)でのスタックオブジェクトの適切なバッファオーバーフローチェックがあります。また、ヒープの定期的なチェックを行います。

問題が発生した場所を追跡するのに役立つのは、後で(検出されたときに)破損したメモリと照合するためにすべての割り当てをダンプするためにマクロを使用し始める傾向がある場所です。

痛みを伴うプロセスなので、より良い方法も学びたいと思っています。

于 2009-11-19T18:37:02.733 に答える
0

私たちのメモリ安全性チェックを検討してください。私はそれがあなたが説明するすべてのエラーを捕らえると思います。はい、それはすべてのアクセスの実行時チェックであり、エラーのある最初のプログラムアクションを診断するという利点を備えたかなりのオーバーヘッド(私たちが考えるvalgrindほど悪くはありません)があります。

于 2011-03-11T03:54:28.107 に答える