segmentation fault 11(core dumped)の原因と2つのチェックポイント

C言語やC++を触っていると、segmentation fault 11(core dumped)というエラーが発生する時がある。

今回は、このsegmentation fault 11(core dumped)の原因や起こった時の対処法を2つ紹介していく。

segmentation fault 11(core dumped)の原因とは?

segmentation fault 11(core dumped)(以下、セグフォ)とは、本来はアクセスできないメモリのアドレスにアクセスする時に起こるエラーのことを言う。

セグフォが起こるケースは、配列やポインタを扱っている時が多い。例えば、以下のコードは、array配列は要素5つしか確保していないのに、10つ目の要素にアクセスしようとしているので、セグフォが起こる。

int main() {
  int arr[5] = {1, 3, 5, 3, 5};
  arr[10] = 2;
  return 0;
}

また、ポインタ変数が指しているアドレスがNULLだったり、メモリを確保していない部分にアクセスしようとすれば、セグフォが発生する。

int main() {
  int *p = NULL;
  *p = 4;
  return 0;
}

segmentation fault 11(core dumped)の対処法

1,gdbとかlldbのツールを使う

Linuxであればgdb、Macであればlldbと言うツールが最初から入っているので、これらでコードのどこの部分でセグフォが発生しているかを特定する。

やり方は簡単で、まずはコードをコンパイルする時に-gオプションをつけてコンパイルする。(例:g++ -g -o main main.cpp C言語の時はg++をgccに変更)

上記の例だとmain実行ファイルができるので、Linuxだとgdb ./main、Macだとlldb -f ./mainとコマンドを実行。そして、rコマンドを実行すると、Quitting LLDB will kill one or more processes. Do you really want to proceed:と言うメッセージが出てくるので、yを押してEnterを押すと、プログラムが実行される。

プログラムを実行すると、僕の場合は以下のようなエラーが発生した。

Process 1270 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x7ffeefc00000)
frame #0: 0x0000000100006944 shogi`Com::alphaBeta(this=0x00007ffeefbfd760, teban=32, b=0x00007ffeefbf74d0, alpha=-9999, beta=1100, depth=4, maxDepth=392701952) at Com.cpp:63:32
60               retval = v;
61               Best[depth][depth] = teBuf[i];
62               for(int i = depth + 1; i < maxDepth; i++) {
-> 63                   Best[depth][i] = Best[depth + 1][i];
64               }
65
66               if(teban == BLACK && alpha < retval) {
Target 0: (shogi) stopped.

上記のエラー文でセグフォを解決するためには、以下の2つをチェックすると良い。

  • 配列の大きさは適切か?
  • 配列やポインタの周辺で行なっているforやwhile、ifは適切に処理しているか?

もし、上記の2つをチェックしても適切な処理をしている場合は、実際にセグフォが起こったコードの前に、セグフォが起こる原因がある可能性が高い

今回のエラー文に記載されている引数をよく見るとmaxDepth=392701952となっているが、本来はmaxDepth = 4となっていないとダメな部分だった。

なので、セグフォが起こった前のコードの、配列やポインタを操作している部分を重点的に確認することでセグフォが解決できるだろう。

2, 配列へのアクセスが正しいかチェックする

特に、配列のアクセスでarray[id -1]のように変数を使って要素にアクセスしている部分をチェックすべきだ。

例えば、下記のコードでは、本来はDirecr[id -16]とすべきなのにDirecr[i -16]となっていることで、変なメモリの場所に配列がアクセスしてしまい(この時にはセグフォにならなかった)、これが原因で他の場所でセグフォが起こってしまった。

if(id >= 16) {
 for(int i = kingPos - Direct[i - 16]; board[i] == EMPTY; i -= Direct[i - 16]) {
    moveToDefendCheck(teban, teNum, teBuf, i, pin);
 }
}