例としてあげられているのは、符号付き整数のオーバーフロー。負の最小値(INT_MAX + 1 => INT_MIN)になると思いがちですが、C言語では未定義となっています。未定義ということなので、データが飛ぼうがコンピュータが爆発しようが文句は言えません。言い換えるとコンパイラが好きなように扱っても良い(標準準拠)ということになります。以下例を見ていきます。
int i, n; for (i = 0; i <= n; ++i) は n = INT_MAX のときに無限ループしそうな気がしますが、INT_MAX + 1 は undefined なので、コンパイラは n の値に関わらずループは n+1 回実行されると解釈し、コードを最適化することが可能です。
このことがバグを誘発します。void f(int n) { /* check overflow */ if (n > n+1) abort; ... } というコードがあったとき、n < n+1 によりオーバーフローチェックがされているように見えますが、 INT_MAX+1 は未定義なのでコンパイラは n > n+1 は常に偽と解釈することが可能です。その結果、if文は取り除かれてしまい、プログラマの思い通りには動作しません。
さて golang ではどうでしょうか?LLVM blog で挙げられていた以下の項目について mailing list に質問してみました。
- Use of an uninitialized variable
- Signed integer overflow
- Oversized Shift Amounts
- Dereferences of Wild Pointers and Out of Bounds Array Accesses
- Dereferencing a NULL Pointer
- Violating Type Rules
GoはCよりプログラマが思ったとおりに動く言語であると言えるでしょう。