Segmentation Fault とは?不正なメモリアクセス
segmentation fault(segfault)は、プログラムが触れる権限のないメモリを読み書きしようとしたときにオペレーティングシステムが引き起こす crash です。
オペレーティングシステムは各プログラムに定められたメモリ領域を与えます。プログラムがその領域の外に手を伸ばしたり、無効なポインタを dereference したり、読み取り専用メモリに書き込んだりすると、OS は segmentation fault で即座にそれを止めます。segfault は、ポインタが誤りうる C や C++ のような手動メモリ管理の言語で最も一般的です。
segfault を引き起こすもの
segfault は、プログラムがアクセスすべきでないメモリにアクセスしたことを意味します。OS はメモリ保護を使って境界を強制し、それを越えると(不正なポインタ、非マネージドコードでの範囲外インデックス)その保護が作動し、その場でプロセスを kill します。
一般的な原因
- null または未初期化のポインタを dereference する。
- 配列の終端を越えて読み書きする(buffer overflow)。
- 解放された後のメモリを使う(use-after-free)。
- OS が読み取り専用としたメモリに書き込む。
なぜマネージドな言語はめったに segfault しないのか
bounds checking と garbage collection を持つ言語(Java、Python、JavaScript)は不正なアクセスを捕捉し、segfault の代わりに exception を投げます。segfault は通常 C、C++、あるいは非マネージドコードへのネイティブ拡張や FFI 呼び出しを介して現れます。
segfault のデバッグ
debugger や core dump は、プログラムがどこで crash したか、その時点のメモリの状態を示します。AddressSanitizer や Valgrind のようなツールは不正なアクセスをより早く捕捉し、多くの場合ポインタを誤用した正確な行を特定します。
簡単な例
C で int *p = NULL; *p = 5; と書くと null ポインタを dereference します。OS は不正な書き込みを検出し、segmentation fault でプログラムを終了させます。
CI における segfault
テストでの segfault は通常、ネイティブコードの本物で決定的なバグですが、flaky なネイティブ依存や壊れた toolchain を示すこともあります。Latchkey は segfault が一時的に見えるとき(既知の flaky なネイティブステップ)に自動 retry する一方、再現する crash はやはり表面化させ、本物のメモリバグが隠れないようにします。
重要なポイント
- segmentation fault は、許可されていないメモリにアクセスしたプログラムを OS が kill することです。
- 原因には null pointer の dereference、buffer overflow、use-after-free があります。
- 主に手動メモリ管理の言語で現れます。マネージドな言語は代わりに exception を投げます。