2014年7月15日火曜日

Xcode5、そのコンパイラーの64ビットにおけるBOOLの扱いについて

Xcode5上のObjective-Cで、32ビットの時は正常なのに、64ビットでだけおかしくなるというバグの解析依頼が来た。

64ビットでおかしくなるのは、主にビット幅による物が多いが、今回はそういうのではなさそうで、ぱっと考えられる原因がなくて難航した。

おかしくなる場所を絞り込んでいった結果、以下のような意外な原因だったので、報告する。

・・・


BOOLで宣言した変数に、YES/NO以外の整数値を入れた場合、その読み出し値が32ビットと64ビットで異なる。

「例」
BOOL flag=2;

本来このような記述そのもの間違いだが、プログラムの開発過程でYES/NOだけでは不十分になって他の値を代入するように変更することはまれにあり、そのときに変数の型を変更し忘れることも(私自身は経験ないが)、あるかもしれない。

このような代入があっても、コンパイラは標準ではエラーにしない(警告もださない)。Objective-CではBOOLはint(charかも)と同等だからである。なので、実行時も書き込みも読み出しも、見かけ上は正常である。

32ビット環境下では、flagを読み出すと2と読める。
ところが、64ビット環境下ではBOOL値に変換される、2は!=0なのでYESとなり1と読み出される。
(読み出し時に変換されているか、書き込み時にすでに変換されているかは不明である。)

すべての場合にそうなるかは未検証だが、少なくともそうなってしまうことがあるというのは確かである。

32ビットと64ビットでのコンパイラの挙動の違いである。
隠れたバグになるので、64ビット対応時には注意。