スタックオーバーフロー

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

スタックオーバーフロー (stack overflow) は、プログラム中での関数呼び出しが多すぎる時に発生する、バッファオーバーフローの一種である。

概要[編集]

オペレーティングシステムや実行オプションによるが、コールスタックに格納できる情報量には上限がある。コールスタックに蓄積するデータ量が多すぎるとスタックは「オーバーフロー」し、プログラム側で対策をとっていなければ通常はクラッシュしてしまう。ただし、スタックオーバーフローの原因となりうるコーディング技法は比較的限定されており、市販ソフトウェアでこれが発生した場合はそのソフトハウスの開発能力が極めて低い事を自白するようなものである。

スタックオーバーフローの一番の原因は再帰による無限ループである。ただし、末尾最適化を実装した言語では末尾再帰をループへ展開することができ、末尾再帰ではスタックオーバーフローは起こらない。末尾再帰はループ処理に最適化されるので、再帰することそれ自体でスタックを消費することが無いからである。

次によくある原因としては、スタック上に巨大な配列を確保しようとすることである。コールスタックに格納できる情報量には上限があるため、巨大な局所変数はコールスタックに格納するのではなくヒープ領域などを明示的に利用すべきである。

さらに他の原因として、関数呼び出しの階層数が深すぎる場合などがある。

C/C++ での例[編集]

関数呼び出しが深すぎる場合[編集]

 int f()
 {
   g();
 }
 
 int g()
 {
   f();  
 }

f()g() を呼び出しているが、g() もやはり f() を呼び出している。交互の呼び出しは終わることがなく、最終的にはスタックオーバーフローが発生する。

巨大な配列をスタックに配置した場合[編集]

 int main()
 {
   int n[1000000000];  // 配列が大きすぎる
   printf("Hello!\n"); // &"Hello!\n" のプッシュがスタックオーバーフローとなる
 }

この場合は、以下のように配列を静的領域に移動するか、

 int n[1000000000];
 int main()
 {
   printf("Hello!\n");
 }

malloc などを使ってヒープ領域に確保すればスタックオーバーフローは回避できる。

 int main()
 {
   int *n = malloc(sizeof(int) * 1000000000);
   printf("Hello!\n");
   free(n);
 }

関連項目[編集]