8

Visual Studio 2010 でコンパイルしたプログラムでスタック オーバーフローが発生しました。スタック (8 KiB) に割り当てられた小さな char 配列を使用して、do-while ブロック内で文字列関連の作業を行うマクロがあります。次に、このマクロを同じスコープで何度も使用する関数があります。そして今、スタックオーバーフローが発生しています。

スタック割り当ては do-while ブロックに対してローカルであると想定していたため、ブロックが終了すると配列は存在しなくなり、関数の全体的なスタック使用量には寄与しなくなりますが、間違っていたようです。

デバッガーを使用すると、関数に入ると _chkstk() が呼び出されることがわかりました。この関数の引数として、その関数内のマクロの各呼び出しからの 8 KiB 配列すべての合計よりもわずかに大きいスタック サイズがあります (他のローカル変数のためにわずかに大きくなります)。

簡単な例を使用して問題を再現しました。

void func(void)
{
    {char a[500000];}
    {char b[500000];}
    {char c[500000];}
    {char d[500000];}
    {char e[500000];}
}

単純なコンソール アプリケーションで main() からこの関数を呼び出すと、スタック オーバーフローが発生します。ただし、ブロック ステートメントを 1 つを除いてすべて削除しても問題なく実行されます。

これが意図したとおりに機能しているかどうか疑問に思っていますか?

関数に必要な合計スタック サイズはどのように計算されますか? 関数に必要なスタック サイズはどのように計算されますか? スタック上の配列は、範囲外になった後でも、関数の合計スタック サイズに影響しますか?

スタック オーバーフローが発生するのはなぜですか?

4

2 に答える 2

2

標準では、これらの変数が必要とするスタック上のスペースの量を正確に定義していない (または実際にスタックに格納されている) ことは確かです。コンパイラは、これらのローカル変数のそれぞれにスペースを割り当てないようにする必要はありません。実際の再利用は、コンパイラの最適化レベルにも大きく依存する可能性があります。そのため、さまざまな最適化レベルでコンパイルすると (または特定の最適化機能を有効/無効にする場合)、異なることが行われる可能性があります。

C++ では、変数を囲むブロックに対してコンストラクタとデストラクタの呼び出しが定義されているため、 を使用するstd::vectorと、ブロックの終了時に (ヒープから割り当てられた) メモリが解放されます。

要約すると、スペースは再利用される可能性がありますが、決して保証されません。

于 2013-05-11T22:09:39.237 に答える
0

これはコンパイラ固有のものだと思います。同じことが GCC でも問題なく機能します。配列はスコープ外に出るとスタックから削除されます (ただし、すべての配列が同じブロックに属している場合は segfault がスローされます)。

于 2013-05-11T22:08:13.980 に答える