2013年1月31日木曜日

Xcode4.6のバグ

Xcode4.6が出た。

「おっ、今回はバグが出ないじゃん」と思ってたら、やっぱりというか案の定というか
バグがいた。

・memcpyで転送サイズがlongサイズの定数倍の時、インライン展開がいらんお世話をする
・double変数のくせに8バイト境界から確保されない

正確にはXcodeのバグというよりコンパイラのバグ。
ARM実機でのみ発現する。

ARMではlongでは4バイト境界、doubleでは8バイト境界から始まっていなければならない。そうしないとアクセス時にCPUが例外を発生してしまう。ところが、Xcode4.6のコンパイラでは事もあろうにそれらをワード境界から確保することがある。

さらに、それを見越してmemcpy()で内容をコピーするようにしたのに、全く要らんことにmemcpy()がインライン展開する際に、サイズが定数(相当)で指定されている場合、常にバイト単位転送ではなく、サイズが4で割り切れる時は4バイト単位転送にしてしまいやがる。これじゃ意味無いじゃん。

定数相当と書いたのは、定数*変数で定数が4バイトの倍数の時も同じということ。

コンパイルオプションに-fno-inline-functionsを入れてみたけど変わらず。これはユーザー関数のインライン展開のみを制御するのかもしれない。
シミュレーター上では86のコードが出力され、86はどの位置からでもいかなるサイズでもアクセス可能なため発現しない。
ARMと86で同じ最適化というか境界配置にしてるんじゃないか?

実機でしか発現しないし、実機でも同じコードでも出る場所と出ない場所があったりして
非常に厄介なバグである。

ということで、バイト単位コピーを所望する場合は、自前で相当関数を実装しなければならないようである。

・・・補足
同じようにインライン展開される関数でも、memcmp()は1バイトづつ比較するしかないから多分大丈夫だろうし、strcpy()も1バイトコピーが必須なので大丈夫だと思う。
引っかかる可能性があるのはmemcpy(相当)の定数サイズ時だけだと思う。

ちなみに、GCCにも同じバグがいるらしい。XcodeはGCCじゃなくなったけど同じということで。

0 件のコメント:

コメントを投稿