この日記はMozillaのプロダクトへの貢献者としての私の成果を中心に、気になったバグやWeb界隈の話題について書いていますが、 断り書きがある場合を除き、いかなる団体のオフィシャルな見解ではありません。あくまでも個人的なものです。 Mozilla Foundation、Mozilla Corporation、及び関連企業の公式情報ではないことに注意してください。

現在、XHTML 1.0 (もどき)から、HTML5なコンテンツに修正中です。古い日記は修正が完了していませんので表示が崩れます。 順次、修正していく予定ですのでしばらくお待ちください。

もずはっく日記(2013年1月)

2013年1月2日

Bug-org 822866 Can't build using MSVC with enable-optimize=-O2 since landing of bug 813445
初回投稿日時: 2013年01月02日10時03分08秒
最終更新日時: 2013年01月02日10時04分13秒
カテゴリ: Mozilla Core Mozilla20 Windows バグ修正
SNS: (list)

Bug-org 813445の修正で、VC++では-O2で最適化ビルドを作ろうとするとコンパイラがクラッシュするというregressionが出ました。もちろんVC++自体のバグなのですが、そうも言ってられません。

パフォーマンスを意識して、メンバを一括でmemcpy()を使ってOR演算や、初期化できるようにしていましたが、コンストラクタや、代入演算子を定義していたため、C++03では、非PODクラスということになるらしく、memcpy()が危険だという助言を、例によってえむけいさんから頂きました。ところが、PODクラスにしてもVC++のクラッシュは修正できませんでした。

そこで、クラッシュした行に着目してみると、以下のようなコードになっていました。

inline EventFlags operator|(const EventFlags& aOther) const
{
  EventFlags flags;
  flags.SetRawFlags(GetRawFlags() | aOther.GetRawFlags());
  return flags;
}

クラッシュしたのは、SetRawFlagsの行です。ここで、それぞれのメソッドの実装は次のようになっています。

inline void SetRawFlags(RawFlags aRawFlags)
{
  MOZ_STATIC_ASSERT(sizeof(EventFlags) <= sizeof(RawFlags),
    "mozilla::widget::EventFlags must not be bigger than the RawFlags");
  memcpy(this, &aRawFlags, sizeof(EventFlags));
}
inline RawFlags GetRawFlags() const
{
  RawFlags result = 0;
  memcpy(&result, this, sizeof(EventFlags));
  return result;
}

試しに、これらのinline指定を削除してみると、コンパイラがクラッシュしなくなりました。ということで、バグはここの最適化にあるようです。

結果的には、operatorUnion()というメソッドに変更し、一度、変数にGetRawFlags()から得た演算結果を保存してから、SetRawFlags()を呼び出すことで、コンパイラのバグを回避しています。

また、非PODクラスのままでは不安が残るので、EventFlagsBaseEventFlagsと名前を変更し、コンストラクタを削除、上述の通り、|=演算子をUnion()というメソッドに置き換えました。

そして、コンストラクタが無いのは不便なので、新たにEventFlagsというコンストラクタだけを追加した派生クラスを用意し、Union()メソッドを使うような局面では、こちらをローカル変数として利用することで、Clear()メソッドをいちいち呼ばなくとも、自動で初期化されるように修正しています。

関連するかもしれないエントリ

bug-org 822866を含むエントリ