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

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

もずはっく日記(2014年9月)

2014年9月25日

Bug-org 1052343 [TSF] crash in msctf.dll@0x2efce
初回投稿日時: 2014年09月25日00時02分04秒
カテゴリ: Mozilla Core Mozilla35 TSF Windows バグ修正
SNS: (list)

Bug-org 1053048のテストケース<textarea>要素でEnterキーをTSFモードで押すと、長時間起動していたPCでは、ランダムにクラッシュするというバグを見つけました。

クラッシュ自体は、OnLockGranted()を呼び出している間に、TSF内部でクラッシュしていたので、ある意味、TSFのバグと言えそうです。

問題のテストケースでは、Enterキーを押した時に、<textarea>要素がリサイズされるため、一旦、フォーカスを失い、また、フォーカスを再度得る、という動作になるのですが、OnLockGranted()を呼び出し中にフォーカスを失うことで、nsTextStore::Destroy()が呼び出され、nsTextStoreが生成・保持していたTSFのオブジェクトの参照をやめた際に、実際に、それらのオブジェクト自体が解放されているようでした。

つまり、TSF内部で直接参照しているこれらのうちのいずれか、もしくは全てが、TSF内部でstrong referenceではなく、weak referenceで管理されていることを意味します。つまり、OnLockGranged()を呼び出している間は、ITextStoreACPインターフェースの実装側、つまり、アプリは、自信が生成したオブジェクトを手放してはいけない、ということになります。

これを解決するために、このバグでは、根本的な挙動に修正を入れました。

これまでは、nsTextStoreは、プロセス起動時にひとつだけ生成され、エディタがフォーカスを持っている間のみ、必要なTSFのオブジェクトを生成して保持し、エディタがフォーカスを失った際に、それらを解放していました。ですが、この疑似シングルトンのような挙動では複雑なケース、例えばドキュメントがロックされている最中にフォーカスが複数回移動するようなケースがあると、破綻しそうです。

そこで、エディタがフォーカスを得る度に、nsTextStoreを生成し、sEnabledTextStoreで掴んでおくようにし、フォーカスを失った際には、sEnabledTextStoreがそれまでのnsTextStoreのインスタンスを手離し、参照カウントがそのままゼロになったら完全に破棄されるようにしました。これで、メンバの複雑な管理には悩まされずに済みます。

続いて、OnLockGranted()を呼び出す前に、nsTextStore自身のインスタンスをスタック上のnsRefPtrで掴んでおき、sEnabledTextStoreが手放しても、参照カウントが絶対にゼロにならないようにし、OnLockGranted()の呼び出し中は、各種インスタンスが解放されないようにしました。

そして、sEnabledTextStoreがクリアされる直前には今まで通り、nsTextStore::Destroy()を呼び出しますが、Destroy()は、ドキュメントをロック中には呼び出された場合には、これを表すフラグを立てるだけにし、実際にメンバの解放は行わないようになりました。その後、RequestLock()の処理が全て終わってから(ドキュメントのロックが解除されてから)、このフラグが立っている場合には、再度Destroy()を呼び出し、クリーンナップを行うようにしました。

まとめると、nsTextStoreは、エディタがフォーカスを得た際に生成され、エディタがフォーカスを失う際に解放されますが、RequestLock()が呼び出されている最中にフォーカスを失った場合のみ、直ちに解放されず、処理が完了後に自動的に解放されます。

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

bug-org 1052343を含むエントリ

このエントリへのリンク元

このエントリを参照しているURIはありません。