2009-03-15 6 views

答えて

14

標準ではスタックを使用する必要はなく、スタックオーバーフローについては何も言及していません。

1

私は、オペレーティングシステムによって何が起こっているかの詳細は明らかですが、すべての場合において、プログラムは終了する必要があります。あなたは、スタックオーバーフローが発生すると(少なくともプログラマーとして)あなたができることは何もないと仮定して正しいです。あなたが本当にやることができるのは、最初に起こらないようにすることです。

1

オペレーティングシステムに依存します。ただし、多くのオペレーティングシステムでは、デフォルトのスタックサイズを上書きすることができます。たとえば、Windowsではthis linker flagを使用して、スタックサイズを1MBから高い値に増やすことができます。

4

Cの標準ではスタックを定義していないため、スタックがオーバーフローしたときに何が起こるかは明確に定義されていません。

2

this questionへのいくつかの回答によれば、Cの標準では、スタックの存在については何も言及していません。

8

C99規格ではスタックが定義されていません。オーバーフロー検出を伴う連続したスタックは、自動ストレージを実装するための1つのメカニズムに過ぎないのに対して、抽象的に自動または割り当てられたストレージについてのみ説明します。

標準の7.14節では、「記憶域への無効なアクセス」で発生するシグナルとしてSIGSEGVを定義しています。。 Cの実装ではシグナルを生成する必要はありませんが、スタックオーバーフローが検出された場合、連続した固定サイズのスタック*を使用する実装は通常、SIGSEGVを通知します。

SIGSEGVのシグナルハンドラ関数を登録することはできますが、-"[i] fを返すことはできません。関数が返ってくると、sigの値がSIGFPE、SIGILL、SIGSEGV、演算例外に対応する定義済み値の場合、behavio [u] rは未定義です "

(私は意図的にCの実装をしていませんが、他の環境で拡張可能な自動ストレージドメインを実装するために使用される一般的な技術の使用を妨げるC標準のものは認識していません)

1

他の人が触れたように、この標準ではスタックについて何も言わない。

しかし、スタックオーバーフローの振る舞いを定義するのが標準だと思います。

::リムショット::

4

ここでの答えは、全体がありますように離れてプロセスを終了するから、それは思われない」というC標準とは何の関係もなく、あなたの声明ではないことを伝えるには正しいです実行可能なロット "は - 一般性として - 真実ではありません。

実際、仮想メモリ管理とオンデマンドページングを備えたほとんどのシステムでは、割り当てられたスタックはかなり小さく(通常は現在使用されているものより4KB以上)、オーバーフロー(ページフォルト割り込みを生成する)スレッドのスタックに別のメモリページを追加します。

スタック制限は、通常は1MBですが、暴走プログラムを防ぐために選択されたかなり任意の数字であり、一般的には絶対的な制限ではありません(IntelプロセッサIIRCを搭載した一部のメモリモデルでしたが)。 1MBの物理メモリを各スレッドに割り当てるのは一般に意味がありません。

0

いくつかのシステムでは、スタックオーバーフローの後に予測可能なものを保証すると、すべての関数呼び出しにかなりのオーバーヘッドが追加されます。したがって、標準では、スタックオーバーフローは未定義のビヘイビアと見なされます。実装が正当なプログラムを実行できる効率を最大化することが目標である場合、これは完全に適切です。

この標準では、関数呼び出しの深さをサポートするための十分なスタックがシステムに備わっている必要もありません。いくつかの有用なプログラム(特に組み込みシステムの世界)は、16バイト未満のスタックで手に入ることができ、必ずしもそれ以上のRAMを確保できない場合があるので、寛大なスタックを必要とするということは、 "donあなたが必要としないものを支払う "。

残念ながら、どのような深さが必要か、どのような種類のスタックが利用できるかをプログラムが判断する方法がないという事実は、未定義の動作に関与しないことが保証されている唯一のプログラムですスタック使用量が最小保証を下回っているもの組み込みシステムの世界の外側では、基本的には、標準がおもちゃよりも大きなプログラムについては何も保証しないということです。

0

この点に関して、C標準は矛盾しています。次のプログラムを考えてみましょう:

void foo(uintptr_t n) 
{ 
    int a; 
    printf("%p\n", (void *)&a); 
    if (n+1) foo(n+1); 
} 
int main() 
{ 
    int a; 
    printf("%p\n", (void *)&a); 
    foo(0); 
} 

このプログラムは完全に適合し、最小限の翻訳限界のいずれかに違反しない、と他の人が言ってきたように、スタックの制限/オーバーフローに関する標準の言語では何もありません。ただし、それぞれの呼び出しレベルでUINTPTR_MAX +2個のオブジェクトaが生成され、その寿命はすべて重複し、それぞれが別個のアドレスを持ちます。これは単なる数え上げの議論では不可能です。