6

バッファオーバーフローについて読んでいました。スタック上のローカル変数のメモリ割り当てについて奇妙なことが 1 つ見つかりました

int f1 ()
{
    char string1[12];
    char string2[4];
}

ここでは、スタック上で割り当てが行われています。

現在、GCCでは string2 に 4 バイトが割り当てられていますが、2 の累乗以外 (最大 16) を宣言すると、コンパイラによって 16 バイトが割り当てられます。つまり、string2 を 3,5,6,7,....,15 バイトに割り当てると、コンパイラによって 16 バイトが割り当てられますが、1,2,4,8 のように 2 の累乗で割り当てると...次に、まったく同じサイズが割り当てられます。16 バイト以上 (2 の累乗ではない) を割り当てると、32 バイトが割り当てられます (最大 32 バイトだと思います)。

一方、Visual Studio では、1 バイトを割り当てると 9 バイトが割り当てられ、2 ~ 4 バイトの場合は 12 バイトが割り当てられ、5 ~ 8 バイトの場合は 16 バイトがコンパイラによって割り当てられます。

なぜこの種の割り当てを知っている人はいますか?

少なくとも Visual Studio では、バッファ オーバーフローが発生するとデバッグ エラーが発生しますが、gcc では何も起こりません。GCC は、大きすぎるオーバーフローが発生した場合にのみ、セグメンテーション違反を提供します。

4

3 に答える 3

13

スタック フレーム サイズは、メモリ アラインメントの選択によって影響を受けます。通常、32 ビット コードでは 4 の倍数、64 ビット コードでは 8 の倍数です。

どちらのコンパイラにも、canaryを使用したスタック フレームの破損チェックを含めることができます。これは、スタックの上部にある追加の 32 ビット値で、関数のエントリで初期化され、関数の終了でチェックされます。カナリア値が変更された場合、関数の戻りアドレスを変更して任意の場所に戻す可能性のある悪意のあるコードによってスタック フレームが破損する可能性があるため、プログラムの中止が発生します。非常に人気のあるマルウェア インジェクション ベクトル。

MSVC には /RTC オプションがあり、デバッグ構成で既定で有効になっています。これにより、これらのカナリアがすべてのローカル変数の間に追加されます。そのため、個々の変数ごとにバッファ オーバーフローの問題を検出できます。

もちろん、これらのカナリアは余分なスペースを必要とし、スタック フレームのサイズに影響します。

于 2013-09-10T11:18:39.150 に答える
5

それはmemory-aligmentによるものです。CPU は、要求されたデータのサイズの倍数であるメモリ アドレスにアクセスする方が簡単です。
そのため、コンパイラは構造体をクリアバイトで埋めて、構造体を整列させます。例えば:

struct foo
{
    char a
    int b , c;
    short d;
    bool e;
    double f;
};

理論的には、その構造体のサイズは (サイズboolが 1 バイト、char1 バイト、int4 バイト、short2 バイト、double8 バイトであると仮定して) 20 バイトです。しかし実際には、コンパイラは構造体に「穴」を追加してメモリを整列させます。

         0 | 1 | 2 | 3
-----------+---+---+---
0x0000 | a |   |   |
-----------+---+---+---
0x0004 | b | b | b | b
-----------+---+---+---
0x0008 | c | c | c | c
-----------+---+---+---
0x000C | d | d |   |
-----------+---+---+---
0x0010 | e |   |   |
-----------+---+---+---
0x0014 | f | f | f | f
-----------+---+---+---
0x0018 | f | f | f | f
-------+---+---+---+---
于 2013-09-10T11:06:43.867 に答える