web-dev-qa-db-ja.com

OSは、malloc / free / new / deleteでメモリを0xCD、0xDDなどに初期化するのはなぜですか?

OSは時々0xCDや0xDDなどの特定のパターンでメモリを初期化することを知っています。私が知りたいのはwhenwhyが起こることです。

いつ

これは使用するコンパイラに固有ですか?

これに関して、malloc/newおよびfree/deleteは同じように機能しますか?

プラットフォーム固有ですか?

LinuxやVxWorksなどの他のオペレーティングシステムで発生しますか?

なぜ

私の理解では、これはWin32デバッグ構成でのみ発生し、メモリオーバーランを検出し、コンパイラが例外をキャッチするために使用されます。

この初期化がどのように役立つかについて、実際的な例を挙げていただけますか?

メモリを割り当て時に既知のパターンに初期化するのが適切であり、特定のパターンがWin32で割り込みをトリガーし、デバッガーで例外が表示されるということを読んだことを覚えています(おそらくCode Complete 2で)。

これはどれくらいポータブルですか?

117

デバッグモード用にコンパイルされたときに、Microsoftのコンパイラが所有/未初期化メモリのさまざまなビットに使用するものの概要(サポートはコンパイラのバージョンによって異なる場合があります):

Value     Name           Description 
------   --------        -------------------------
0xCD     Clean Memory    Allocated memory via malloc or new but never 
                         written by the application. 

0xDD     Dead Memory     Memory that has been released with delete or free. 
                         Used to detect writing through dangling pointers. 

0xED or  Aligned Fence   'No man's land' for aligned allocations. Using a 
0xBD                     different value here than 0xFD allows the runtime
                         to detect not only writing outside the allocation,
                         but to also detect mixing alignment-specific
                         allocation/deallocation routines with the regular
                         ones.

0xFD     Fence Memory    Also known as "no mans land." This is used to wrap 
                         the allocated memory (surrounding it with a fence) 
                         and is used to detect indexing arrays out of 
                         bounds or other accesses (especially writes) past
                         the end (or start) of an allocated block.

0xFD or  Buffer slack    Used to fill slack space in some memory buffers 
0xFE                     (unused parts of `std::string` or the user buffer 
                         passed to `fread()`). 0xFD is used in VS 2005 (maybe 
                         some prior versions, too), 0xFE is used in VS 2008 
                         and later.

0xCC                     When the code is compiled with the /GZ option,
                         uninitialized variables are automatically assigned 
                         to this value (at byte level). 


// the following magic values are done by the OS, not the C runtime:

0xAB  (Allocated Block?) Memory allocated by LocalAlloc(). 

0xBAADF00D Bad Food      Memory allocated by LocalAlloc() with LMEM_FIXED,but 
                         not yet written to. 

0xFEEEFEEE               OS fill heap memory, which was marked for usage, 
                         but wasn't allocated by HeapAlloc() or LocalAlloc(). 
                         Or that memory just has been freed by HeapFree(). 

免責事項:表は、私が横たわっているいくつかのメモからのものです-それらは100%正しい(または首尾一貫した)ものではないかもしれません。

これらの値の多くは、vc/crt/src/dbgheap.cで定義されています。

/*
 * The following values are non-zero, constant, odd, large, and atypical
 *      Non-zero values help find bugs assuming zero filled data.
 *      Constant values are good so that memory filling is deterministic
 *          (to help make bugs reproducable).  Of course it is bad if
 *          the constant filling of weird values masks a bug.
 *      Mathematically odd numbers are good for finding bugs assuming a cleared
 *          lower bit.
 *      Large numbers (byte values at least) are less typical, and are good
 *          at finding bad addresses.
 *      Atypical values (i.e. not too often) are good since they typically
 *          cause early detection in code.
 *      For the case of no-man's land and free blocks, if you store to any
 *          of these locations, the memory integrity checker will detect it.
 *
 *      _bAlignLandFill has been changed from 0xBD to 0xED, to ensure that
 *      4 bytes of that (0xEDEDEDED) would give an inaccessible address under 3gb.
 */

static unsigned char _bNoMansLandFill = 0xFD;   /* fill no-man's land with this */
static unsigned char _bAlignLandFill  = 0xED;   /* fill no-man's land for aligned routines */
static unsigned char _bDeadLandFill   = 0xDD;   /* fill free objects with this */
static unsigned char _bCleanLandFill  = 0xCD;   /* fill new objects with this */

また、デバッグランタイムがバッファ(またはバッファの一部)を既知の値(たとえば、std::stringの割り当ての「スラック」スペースまたはfread()に渡されるバッファ)で埋める場合もあります。これらのケースでは、_SECURECRT_FILL_BUFFER_PATTERNcrtdefs.hで定義)という名前の値を使用します。いつ導入されたのか正確にはわかりませんが、少なくともVS 2005(VC++ 8)まではデバッグランタイムにありました。

当初、これらのバッファを埋めるために使用される値は0xFDでした。これは人のいない土地に使用されるのと同じ値です。ただし、VS 2008(VC++ 9)では、値は0xFEに変更されました。これは、たとえば呼び出し元がfread()には大きすぎるバッファサイズを渡した場合など、フィル操作がバッファの最後を超えて実行される可能性があるためだと思います。その場合、値0xFDはこのオーバーランの検出をトリガーしない可能性があります。バッファサイズが1つだけ大きすぎると、フィル値はそのカナリアを初期化するために使用されるno manのランド値と同じになるからです。誰の土地にも変化がないということは、オーバーランに気付かないことを意味します。

そのため、VS 2008では塗りつぶしの値が変更されたため、このような場合はノーマンのランドカナリアが変更され、ランタイムによって問題が検出されます。

他の人が指摘したように、これらの値の重要なプロパティの1つは、これらの値の1つを持つポインタ変数が逆参照されることです。標準の32ビットWindows構成ではユーザーモードアドレスは0x7fffffffよりも高くなります。

180
Michael Burr

フィル値0xCCCCCCCCに関する素晴らしいプロパティの1つは、x86アセンブリでは、オペコード0xCCが int オペコードであり、これはソフトウェアブレークポイント割り込みです。そのため、その初期化されていないメモリでそのfill値で満たされたコードを実行しようとすると、すぐにブレークポイントにヒットし、オペレーティングシステムはデバッガをアタッチ(またはプロセスを強制終了)します。

33
Adam Rosenfield

コンパイラーおよびOS固有であるため、Visual Studioはさまざまな種類のメモリをさまざまな値に設定するため、デバッガーでmallocされたメモリ、固定配列、または初期化されていないオブジェクトにオーバーオーバーしたかどうかを簡単に確認できます。私がそれらをグーグルしている間に誰かが詳細を投稿します...

http://msdn.Microsoft.com/en-us/library/974tc9t1.aspx

7
Martin Beckett

OSではなく、コンパイラです。動作も変更できます-この投稿の下部をご覧ください。

Microsoft Visual Studioは、スタックメモリに0xCCを事前に入力するバイナリを(デバッグモードで)生成します。また、バッファオーバーフローを検出するために、すべてのスタックフレームの間にスペースを挿入します。これが役立つ非常に簡単な例はこちらです(実際にはVisual Studioはこの問題を見つけて警告を出します)。

...
   bool error; // uninitialised value
   if(something)
   {
      error = true;
   }
   return error;

Visual Studioが変数を既知の値に事前初期化していない場合、このバグを見つけるのは難しい可能性があります。事前初期化された変数(または、事前初期化されたスタックメモリ)を使用すると、実行のたびに問題を再現できます。

ただし、わずかな問題があります。 Visual Studioが使用する値はTRUEです。0以外はすべてTRUEになります。実際、リリースモードでコードを実行すると、ユニタライズされた変数がたまたま0を含むスタックメモリに割り当てられる可能性があります。つまり、リリースモードでのみ現れるユニタライズされた変数のバグがある可能性があります。

それは私を悩ませたので、私は スクリプトを書いた バイナリを直接編集して事前入力値を変更し、スタックにゼロが含まれている場合にのみ現れる初期化されていない変数の問題を見つけることができました。このスクリプトは、スタックの事前入力のみを変更します。ヒープの事前入力を試したことはありませんが、可能です。ランタイムDLLの編集が必要な場合がありますが、そうでない場合があります。

4
Airsource Ltd

これは使用するコンパイラに固有ですか?

実際、ほとんどの場合、ランタイムライブラリの機能です(Cランタイムライブラリなど)。通常、ランタイムはコンパイラと強く相関していますが、交換できる組み合わせがいくつかあります。

Windowsでは、デバッグヒープ(HeapAllocなど)も、デバッグCランタイムライブラリのmallocおよびfree実装から来るものとは異なる特別なfillパターンを使用します。そのため、OSの機能でもありますが、ほとんどの場合、それは単なる言語ランタイムライブラリです。

これに関して、malloc/newおよびfree/deleteは同じように機能しますか?

通常、newおよびdeleteのメモリ管理部分はmallocおよびfreeで実装されるため、newおよびdeleteで割り当てられたメモリは通常同じ機能を持ちます。

プラットフォーム固有ですか?

詳細はランタイム固有です。使用される実際の値は、16進ダンプを見たときに異常で明白に見えるだけでなく、プロセッサの機能を活用できる特定のプロパティを持つように設計されていることがよくあります。たとえば、アラインメントフォールトを引き起こす可能性があるため、奇数値がよく使用されます。 (0ではなく)大きな値が使用されます。これは、初期化されていないカウンターにループすると驚くほどの遅延が発生するためです。 x86では、0xCCはint 3命令なので、初期化されていないメモリを実行すると、トラップされます。

LinuxやVxWorksなどの他のオペレーティングシステムで発生しますか?

それは主に、使用するランタイムライブラリに依存します。

この初期化がどのように役立つかについて、実際的な例を挙げていただけますか?

上記をいくつかリストしました。通常、値は、メモリの無効な部分で何かを行うと異常が発生する可能性を高めるために選択されます:長い遅延、トラップ、アライメントフォールトなど。これらのパターンが変更された場合、どこかで不正な書き込み(バッファオーバーランなど)があったことがわかります。

メモリを割り当てたときに既知のパターンにメモリを初期化するのが良いことを読んだことを覚えています(コードコンプリート2で)、特定のパターンはWin32で割り込みをトリガーし、デバッガで例外が表示されます。

これはどれくらいポータブルですか?

ソリッドコードの作成(そしておそらくコード完了)塗りつぶしパターンを選択するとき。私はここでそれらのいくつかに言及しました、そして、ウィキペディアの記事 マジックナンバー(プログラミング) はそれらを要約します。いくつかのトリックは、使用しているプロセッサーの仕様に依存します(アライメントされた読み取りと書き込みが必要かどうか、どの値がトラップする命令にマップされるかなど)。メモリダンプで際立っている大きな値や異常な値を使用するなど、他のトリックはより移植性があります。

3
Adrian McCarthy

「理由」の明白な理由は、次のようなクラスがあると仮定することです。

class Foo
{
public:
    void SomeFunction()
    {
        cout << _obj->value << endl;
    }

private:
    SomeObject *_obj;
}

そして、Fooをインスタンス化し、SomeFunctionを呼び出すと、0xCDCDCDCD。これは、何かを初期化するのを忘れたことを意味します。それが「理由」です。そうでない場合は、ポインターが他のメモリと整列している可能性があり、デバッグがより困難になります。アクセス違反が発生した理由を知らせるだけです。このケースは非常に簡単でしたが、より大きなクラスではその間違いを犯しやすいことに注意してください。

知る限り、これは(リリースではなく)デバッグモードのVisual Studioコンパイラでのみ機能します

2
FryGuy

実行中にプロセスにデバッガーをアタッチできるため、一般的にデバッグ中にメモリが初期開始値から変更されたことが簡単にわかります。

メモリだけでなく、多くのデバッガーは、プロセスの開始時にレジスターの内容をセンチネル値に設定します(AIXのバージョンによっては、いくつかのレジスターを0xdeadbeefこれは少しユーモラスです)。

2
paxdiablo

この記事では、 異常なメモリビットパターン と、これらの値に遭遇した場合に使用できるさまざまな手法について説明します。

2
Stephen Kellett

IBM XLCコンパイラには、指定した値を自動変数に割り当てる「initauto」オプションがあります。デバッグビルドには次を使用しました。

-Wc,'initauto(deadbeef,Word)'

初期化されていない変数のストレージを見ると、0xdeadbeefに設定されます

1
Anthony Giorgio