Code Fix

上級

Segmentation fault(配列の範囲外への書き込み)

配列の宣言サイズを大きく超えた添字に書き込むと、プロセスに割り当てられていないメモリ領域に触れてクラッシュします。

エラーメッセージの読み方

Segmentation fault
(エラーメッセージなし)
これはプログラム自身の出力ではありません。プログラムは何も言わずに落ちています
Segmentation fault
シェルが検知した異常終了の種類 — OSが「不正なメモリアクセス」などを検出しプロセスを強制終了させました
見つけ方
このメッセージだけでは行番号すら分かりません。原因はコードを読んで特定するしかありません

このエラーが出る典型パターン

パターン1

 1  #include <stdio.h>
 2  
 3  int main(void) {
 4      int scores[5] = {1, 2, 3, 4, 5};
 5      scores[100000000] = 99;
                   ^
 6      printf("%d\n", scores[0]);
 7      return 0;
 8  }
Segmentation fault

配列の宣言サイズを大きく超えた添字に書き込むと、プロセスに割り当てられていないメモリ領域に触れてクラッシュします。

直し方: 100000000 を 0 にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  #include <stdio.h>
 2  
 3  int main(void) {
 4      int data[10];
 5      data[999999999] = 1;
                 ^
 6      printf("%d\n", data[0]);
 7      return 0;
 8  }
Segmentation fault

少しだけ超えた添字は近くの別の変数を静かに破壊するだけでクラッシュしないこともありますが、大きく外れた添字ではOSがメモリ保護違反として検出しクラッシュさせます。

直し方: 999999999 を 0 にします。

この問題を解いてみる →

パターン3

 1  #include <stdio.h>
 2  
 3  int main(void) {
 4      int buffer[3];
 5      buffer[50000000] = 5;
                   ^
 6      printf("%d\n", buffer[0]);
 7      return 0;
 8  }
Segmentation fault

配列が小さいほど、少し大きめの添字を渡しただけでもプロセスの外の領域に触れやすくなります。

直し方: 50000000 を 0 にします。

この問題を解いてみる →

パターン4

 1  #include <stdio.h>
 2  
 3  int main(void) {
 4      int arr[6] = {1, 2, 3, 4, 5, 6};
 5      arr[200000000] = 42;
                ^
 6      printf("%d\n", arr[0]);
 7      return 0;
 8  }
Segmentation fault

配列の宣言サイズを大きく超えた添字への書き込みは、プロセスの外の領域に触れてクラッシュします。

直し方: 200000000 を 0 にします。

この問題を解いてみる →

パターン5

 1  #include <stdio.h>
 2  
 3  int main(void) {
 4      int vals[4];
 5      vals[750000000] = 7;
                 ^
 6      printf("%d\n", vals[0]);
 7      return 0;
 8  }
Segmentation fault

配列が小さいほど、大きくずれた添字でメモリ保護違反を起こしやすくなります。

直し方: 750000000 を 0 にします。

この問題を解いてみる →

よくある誤解

「範囲外アクセスは必ずクラッシュする」わけではありません。少しだけ超えた場合は近くの別の変数を静かに破壊するだけでクラッシュしないこともあります(発見はむしろこちらの方が困難です)。大きく外れた添字の場合にのみ、OSがメモリ保護違反として検出しクラッシュさせます。

実務での勘所

クラッシュするかどうかの境目は、OSのメモリ保護が「ページ」という単位(x86系では通常4KB)でしか働かないことに関係しています。範囲外への書き込みが、たまたま同じページ内に確保されている他のデータの領域にとどまっていれば、OSはそれを異常として検出できず、静かに他の変数やデータ構造を破壊するだけで済んでしまいます。書き込みがページの境界を越えて、プロセスに割り当てられていない領域にまで達して初めて、OSがハードウェアの例外を検出してクラッシュさせます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)