2011年5月30日月曜日

C言語の未定義動作と golang

LLVM の blog  What Every C Programmer Should Know About Undefined Behavior を読みました。C言語の未定義動作と、最適化過程において一見正しそうにみえるバグを生み出す例が載っています。
例としてあげられているのは、符号付き整数のオーバーフロー。負の最小値(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よりプログラマが思ったとおりに動く言語であると言えるでしょう。

0 件のコメント:

コメントを投稿