3

Visual Studio 2012 (2012 年 11 月 CTP コンパイラを使用) で場所 0xFEEEFEF6 を読み取っているときに、C++11 同時実行実装の奥深くでアクセス違反に遭遇しました。

この値に特別な意味はありますか? ウィキペディアを見ると、同様のエントリ ( 0xFEEEFEEEおよび0xFEEDFACE ) が見つかりました。

4

1 に答える 1

6

0xFEEEFEF6それ自体には特別な意味はありませんが、MSVC がヒープ割り当てに好んで配置する「ガード バイト」セグメントの 1 つに基づいている可能性があります。Jan Dvorak が指摘したように、おそらく何かの終わりから 8 バイト後、配列の終わりから 2 ポインター後という可能性が非常に高いです。

この概念は、誤ってアクセスする可能性が高いがアクセスしてはならないメモリが、非常に明白なパターンでマークされているということです。最も一般的なのは0xCDCDCDCD0xFDFDFDFDですが、0xDDDDDDDD0xFEEEFEEEにも簡単に遭遇します。古典的なコンパイラ (まだ使用しているかどうかは不明) が好きでし0xDEADBEEFた。これは、ガードバイトが見られるケースと位置のかなり良い記事です.

segfault (アクセス違反) でこれらを確認する最も一般的な 2 つの原因は、通常、既に解放されているメモリへのアクセスと、特にポインターの配列での境界のオーバーランです。ガード データに使用される値のほとんどは、それ以外の場合にアプリに表示される場合は有効ではありません (0x00000000またはでメモリ ブロックを取得することはありません。0xCDCDCDCDこれらは、ヒープが存在する仮想アドレス空間のかなり外側にあります)。 )。一般的なものを頭のてっぺんから知っておくと、デバッグの時間を大幅に節約できます。

例外はほとんどないかまったくないため、これらのガード バイトはデバッグ ビルドでのみ表示されることに注意してください。割り当て/割り当て解除のたびに特別なパターンでメモリを書き込むこと (実際には、ほとんどのガード パターンは割り当てられたチャンクの境界で発生するため、割り当てられたよりもはるかに多くのメモリを書き込むこと) はかなりコストがかかるため、実行時に行うべきではありません。デバッグ ビルドでこのような問題が発生した場合、リリース ビルドから一見ランダムな (未定義の) アドレスを取得する可能性があります。また、不運にも正当なアドレスが誤って取得されてしまい、あらゆる種類のヒープの破損につながる可能性があります。

ガード バイトはリリース ビルドには表示されないため、通常のようにチェックしNULLてコード内の条件として使用することはできません。代わりに、スマート ポインターとコンテナーを使用すると、メモリを正しく管理し、最初から不適切なアクセスを回避できます。面倒なこともありますが、スマート ポインターはこのような問題を回避するのに非常に役立ちます。一部の種類のアクセス違反、特にバッファ オーバーランは、その発生頻度からセキュリティ脆弱性の全体クラスと見なされることに注意してください。

VM/ランタイムが特定のメモリ制約内にとどまることを強制することなく、メモリへのアクセスが非常に簡単である場合は、そうすべきではありません。例えば:

int values[10];
int output = 0;
int length = 10;
while (int i <= length) {
    output += values[++length];
}

prefix-increment を使用すると、配列の末尾を使い果たしvalues[10]、無効なインデックスである にアクセスすることになります。すぐにアクセス違反が発生してプログラムが停止する場合もあれば、アクセスが許可されているメモリに値が追加される場合もあります。outputこれにより、オーバーフローが発生しoutput、アプリの残りの部分で予期しない動作が発生する可能性があります。

ガード バイトが存在するのは、デバッグ中にセグメンテーション違反またはインクリメントが繰り返し可能な値を持ち、可能な限り明確になるようにするためです。

于 2013-06-12T18:29:58.420 に答える