Segmentation Faultの傾向と対策


このエントリーをはてなブックマークに追加

C/C++のコードを書いてよく遭遇するのがSegmentation Fault、通称セグフォ。その傾向と対策をまとめてみた。

傾向

セグフォがよく起こるのは以下のとき。

メモリ違反

見てはいけないメモリ領域を参照したときに起こる。コード例は以下。

#include <stdio.h>

int main(){
    int array[10];
    int i;
    for(i = 0; i < 20; ++i){
        array[i] = i;
    }
    return 0;
}
無限再帰 または 再帰が深すぎる

関数の無限再帰から抜け出せない時にもセグフォが起こる。コード例は以下。

#include <stdio.h>

void loop(){
    loop();
}

int main(){
    loop();
    return 0;
}

また、理論上はどこかで再帰が終わるはずであっても、あまりに再帰が深すぎる場合も、やはり同様にセグフォが発生する。

対策1:セグフォの発生場所を特定する

セグフォを起こした場所を特定するには、ダンプされたcoreを使うとよい。

coreを出力

まず、コアファイルが出力される設定になっているか確認する。

$ ulimit -c

して、0が表示されるようであれば以下のコマンドを実行する。これでコアファイルが出力される。

$ ulimit -c unlimited
コンパイル

gccコンパイルする時-gオプションを忘れずに入れる。

$ gcc -g loop.c
実行

実行ファイルを実行するとcore.(プロセス番号)が出力される。

$ ./a.out
デバッグ

コアファイルを使って、どこでセグフォが起きたかを特定する。

$ gdb a.out core.(プロセス番号)

よく使うコマンドは以下。

  • backtrace
    • 関数の呼び出し順を確認
  • frame n
    • backtraceで表示されている関数のうち、n番目の関数に移動
  • info locals
    • ローカル変数の一覧を確認
  • info args
    • 引数の一覧を確認
  • print val
    • 変数valの値を表示
Cygwinの場合のコアファイルの生成方法

Cygwinでは、デフォルトで、coreファイルの代わりにa.exe.stackdumpとかいうファイルが生成される。coreファイルを生成する方法がに書かれていた。ただし私は未確認。

対策2:スタックサイズを変更する

再帰が深すぎるためにセグフォが発生している場合は、スタックサイズを変更することでセグフォを回避できることがある。

例えばgccの場合は以下のようにしてスタックサイズを変更できる。

gcc -Wl,--stack,4194304 program.c

Visual Studio 2013 の場合は、プロジェクトのプロパティ→リンカー→システム→スタックのサイズの設定 に適切な値を入力することでスタックサイズを変更できる。