0

時折、リリース ビルドや一部のマシンでのみ再現可能なバグに遭遇することがあります。一般的な (決してそれだけではない) 理由は、初期化されていない変数であり、ランダムな動作をする可能性があります。たとえば、初期化されていない BOOL は、ほとんどのマシンでほとんどの場合 TRUE になりますが、ランダムに FALSE として初期化されます。

私が望んでいるのは、CRT メモリの初期化の動作を変更して、このようなバグを洗い流す体系的な方法です。私は MS デバッグ CRTマジック ナンバーをよく知っています。少なくとも、0xCDCDCDCD (新たに割り当てられたメモリを初期化するパターン) をゼロにするトリガーが必要です。デバッグビルドであっても、この方法で厄介な初期化害虫を簡単に吸い出すことができると思います。

これを可能にする利用可能な CRT フック (API、レジストリ キーなど) がありませんか? そこにたどり着くための他のアイデアはありますか?

[編集:]説明が整っているようです。

  1. 通常のマジック ナンバーには確かに多くの利点がありますが、bool の初期化 (常に true)、個々のビット マスクに対してテストされるビット フィールド、または同様のケースをカバーしていません。一貫したゼロ初期化 (もちろん、オンとオフを切り替えることができます) は、他の方法ではまれな初期化動作の悪さを表面化させる可能性があるテストのレイヤーを追加します。
  2. もちろん、私はCrtSetAllocHookを知っています。このように設定されたフックは、割り当てられたバッファーへのポインターを受け取らない (そのようなバッファーが割り当てられる前に呼び出される) ため、それを上書きすることはできません。global new をオーバーロードしても、有効なコンストラクターの初期化が上書きされるため、あまり効果がありません。

[編集:] @Michael、new をオーバーライドする意味がわからない。次のような単純なコード -

void* new(...)
{
   void* res = ::new(...);   // constructors now called!
   if(SomeExternalConditionApplies())
      OverWriteBufferWithMyPetValues(res);
}

動作しません。::new コード全体を貼り付けて変更するとうまくいくかもしれませんが、ちょっと怖いようです (神は、実行するために #include してリンクする必要があることだけを知っています)。

4

3 に答える 3

3

私はフォローしていません-初期化されていないメモリ0xcdcdcdcdを0ではなくのようなものに設定すると、コードが「範囲内」の算術演算を取得するか、特別に0を処理する可能性が高いため、バグをフラッシュするのに適しています。 「速く失敗する」ので、非表示にする代わりに修正できます。

MSVCのデバッグビルドが使用する値は、簡単に検出できる障害の原因となるように特別に設計されています。

  • それらは0ではないので、初期化されていないメモリに対するNULLポインタチェックはバグを隠しません
  • それらは有効なポインタではないため、初期化されていないポインタを逆参照するとアクセス違反が発生します
  • これらは「通常の」整数値ではないため、初期化されていないデータを含む計算では、通常、非常に不正確な結果が発生し、目立った障害が発生する傾向があります(署名されたデータとして処理する場合はマイナスになると思いますが、これには少し役立ちますが、それほど多くはありません単に異常な数であるように)。

また、デバッガーのデータ表示で簡単に認識できます。ゼロはそれほど目立ちません。

とはいえ、MSVCには、必要な操作に沿って何かを実行するために使用できる可能性のあるデバッグフック/APIがいくつか用意されています。

更新された質問に対する追加情報:

Dmalloc(http://dmalloc.com/)のようなサードパーティのデバッグ割り当てライブラリを使用できる場合もありますが、これらのライブラリをMSVCプロジェクト、特に「実世界」のプロジェクトに統合するのがどれほど簡単かは正直わかりません。

また、これらは明らかに動的割り当てのみを処理することに注意してください(MSVCのデフォルトの実装とうまく統合されない可能性がありますnew)。

のグローバルオーバーライドを使用して、C ++で使用して発生する割り当てを処理できます-有効なコンストラクターの初期化を上書きしても問題はありません-コンストラクターが初期化を実行する前に割り当てが発生します(少し考えてみると、明確になっているはずです)なぜですか)。operator new()newnew

また、Visual Studio 2010への移行を検討することもできます(初期化されていないローカル変数を使用するとデバッガーに侵入します)。デバッガーでDebugビルドを実行する以外に特別なことは何もしません。もちろん、MSCVはしばらくの間、これらの状況の多くについて警告してきましたが、VS2010はデバッガーで次のことをキャッチします。これにより、警告は生成されません(少なくとも現在のコンパイラ設定では)。

int main(  )
{
    unsigned int x;
    volatile bool a = false;

    if (a) {
        x = 0;
    }

    printf( "Hello world %u\n", x); // VS2010 will break here because x is uninitialized

    return 0;
}

ExpressバージョンのVC++2010でもこれをサポートしています。

于 2010-05-04T22:24:41.087 に答える
1

ただの提案:コンパイラで静的コード分析ツールを使用できますか?/ analysisは、初期化されていないメモリを使用していることを示すC6001警告を表示します。そしてそれはやや体系的であり、それがあなたが求めているものです。

于 2010-05-05T04:46:39.923 に答える
1

CRT に足を踏み入れると、マジック ナンバーが _heap_alloc_dbg と realloc_help で使用され、値自体が次のようにエンコードされていることがわかります。

static unsigned char _bCleanLandFill  = 0xCD;   /* fill new objects with this */

何を検索すればよいかを知っておくと役立つことがよくあります。リンクされたスレッドには良い提案があります: _bCleanLandFill にウォッチを設定し、デバッガーから変更します。

それは機能しますが、この質問はしばらく開いたままにします-誰かがより良いアイデアを持っていることを願っています...制御された初期化で自動テストを実行し、手動で行う必要はありませんでした(そしてデバッガーが利用可能)。

于 2010-05-05T05:48:18.220 に答える