My Hacking

My Win32 Hacking

私の Win32 ハッキングの履歴とテクニックです。

Mozilla C++ モジュール部分のバグ取りに参加したい方はMozilla解体新書をよむことが一番なわけですが、そこにない主に Windows 限定のわたしの Tips をかいてみます。

今までにわたしが追求にまともに参加できたバグは・・・。

です。

Windos でのハッキング

Windows でのハッキング特有の事情については、まずこの3文書をよみましょう。

ここに記述のないテクニックについては、それぞれの追求ページにかいていきます。

ちなみに、Pen4 1.6A+メモリ512M+WinXP で、フルビルドが1時間半程度。cvs で2ヶ月前のソースを取ってきて差分ビルドもそれくらい。数カ所の修正による手元の再ビルドが場所によって15〜40分くらい。cvs を使わないで手元でソースを修正して再ビルドするときには、ソースの変更箇所に関係あるところだけ再ビルドできるように Makefile.in の不要箇所をコメントアウトすると、ちょっとだけはやくなります。例はこちら。

ちなみに、1999年に Netscape からでた Netscape Mozilla Source Code Guide によると、当時のソースは、Pentium Pro 200MHzで30分でビルドできたそうです(m一桁の大昔です)。

ちなみに、Norton のようなリアルタイムスキャンソフトを入れている人の場合、ソースの入っているフォルダをリアルタイムスキャン対象から除外すれば、若干ビルドは早くなります。扱っているファイル数が尋常ではないので、CPU 増強だけではなくHDD のストライピングも若干効果があります。

Bug-JP 320 の追求

これについては、当該バグとMozilla解体新書の追求ページに詳しいのですが、私がやったことを補足しておきます。

何はともあれ MSDN をよむ。まぁ、WinAPI がからむバグにたいしてはほかの日本のハッカーもされていることなので、特に記述することもないのですが、当然でしょう。

デバッグコードを入れる。デバッグのビルドだと、コンソールに printf で表示をだせるので、積極的に利用しましょう。というか、こと Mozilla のビルドに限定して Win でデバッガ(例:VC++)で C++ のソースコードレベルでブレークポイントを設定したりする方法をしらないので、ベタベタなデバッグをしてしまいます。

スタンドアロンの検証プログラムをつくる。これもあたりまえのことですが。。。

そうじて、わたしがこのバグでやったことは、上記のテクニック(?)で神尾さんの理論のうらづけをとったことといってよいでしょう。

Bug-JP 2515 の追求

Mac OS X の Mozilla Suite と Firefox では出ないそうだ。Camino は再現する。原因は不明。

Bug-JP 320でちょっとだけ読めた知識を元に簡単に解析してみたところ、解析結果は神尾さんに的はずれを指摘されてしまいました。外部仕様面でも、実装面でも大変そうという結論が一度出たので、いったん本家頼みで待ってはみたものの、放置プレイは全然終わらず。

仕様面について、non-editable フィールドでは IME は常時オフにしては、という片貝さんの意見に一度は賛成してみたものの、気づいて見れば、不十分ならが Find As You Type でも IME が使えてしまっていることにある日気づいて、「だめじゃん」と思ったのでした。

それを前提に仕様を考えると、他のブラウザとの比較やMozilla内部でのコンポーネント間のIME処理の引き継ぎを考えると、未確定の文字列は、この際には捨てるのがベストのようでした(Find As You Typeの文字を他で引き継ぎたいとは普通思わないでしょうし)。もちろん、途中の文字列は確定する、とか、未確定のまま引き継ぐ、という選択肢もないわけではありません。

そうすると、とりあえず、non-editable フィールドから Textarea に入った際に、無条件に変換途中文字列を捨てる、というアイディアを思いつきました。でも、これは問題があって、Textarea で未確定中に、メニューバーに行って、そのあと戻ってきた時に消えては困ります。ちなみに、non-editable と Textarea の出入り自体を示すメッセージは、nsEditor に飛んできている形跡を見つけられませんでした。もっとちゃんと探さないと?nsEditorは、Textareaが必ず持っている文字の保持と表示を司るクラスです。

さて、調べました。nsEditorは、神尾さんの指摘に近く、mInIMEModeというメンバ変数が未確定処理中であるかどうかを判定しています。このフラグを見て、IME 処理と non-IME 処理を切り分けるのが失敗しています。これは IME 未確定処理中であることを知らないからです。さて、で、調べてみると、これを継承している nsPlainTextEditor を通して nsEditor が使われているようで、なんとnsPlainTextEditor には、未確定文字列の挿入処理のメソッド(SetCompositionString)が呼ばれて、そこから nsEditor::InsertTextIntoTextNodeImpl が呼ばれ、こいつが混乱しています。前者はいわば stateless に Composition だと知っているのに後者が state で誤解している、と。何か変な構造ですが、忘れましょう。この辺りのソースを見ると、時々stateが混乱したときには強制的に処理を切り替えているとおぼしきコードが散見されます。もしかして、単にIME周りの処理はべたべたに汚いだけかもしれません。ここで、中には、mInIMEMode が on(PR_TRUE) の時に、強制的に IME 未確定処理を終わらせるメソッドとして nsEditor::ForceComposisionEnd があるのに気づきます。ここで思いました。SetCompositionString なのに mInIMEMode が PR_FALSE でいやがったら、nsEditor::ForceComposisionEnd を呼んでやれ、と。そうすれば、とりあえず確定処理が走る。これで、バグ自体は治りました(WinXP のみの検証)、が仕様としては気にりません。

・・・が、とてもad hocな修正で、レビュー通るとはあまり思えません。

それから、ForceCompositionEnd さんは、未確定文字列をCompleteする処理が混じっています。では、これを分離してしまえば・・・というアイディアが思いつきます。そうすると、nsWindow から含めていろいろいじることになりました。・・・しかし、これでは一文字消えてしまう。。。

一般に、マウス入力やキー入力は、OS からイベントという形でアプリケーション(Mozilla)へメッセージ送信されるわけですが、このメッセージは OS ごとに差異があるので、Mozilla では、これを抽象化して、さらに DOM イベントなどコンポーネントへのイベントへ変換して、OS からアプリケーションへのメッセージに類する形で、各コンポーネント(Textarea、など)へメッセージを送っています。で、なぜかTextareaがフォーカスを受け取った、もしくは Find As You Type がフォーカスを失った、といったメッセージが各コンポーネントに飛んできているのが見つけられないんですね。。。そういうメッセージ処理があれば、そこで処理するのがベストなんですが。

中野さんが引き継いでくれて Fix。仕様に若干迷いがあるのですが。中野さんは延々と IME は OS に任せるべきだと言っていますが、これだけクロスプラットフォームを目指して中で色々 IME の制御に口を出している(大量の抽象化もしている) Gecko にて、小手先で OS に任せるのは色々無理があるなと思います。

Bug-JP 2465 の追求

これについてのわたしのデバッグテクニックを披露します。

といっても、別のバグにて、同現象について私より2週間はやく同一パッチがでていたのが放置されていて、なぜかわたしのかいたバグのもののほうがチェックインのあつかいになった不思議なバグです。

あやしいところにわざとおちるコードをいれる。Mozilla は高度にモジュール化されているため、どこでなにがよびだされているか新参者がソースだけよんで把握するのには相当時間がかかります。必要そうな部分についてそれをしるために、ほんとうなら、あやしいところにデバッガでブレークポイントを入れてトレースをみて調査したいところですが、それのやりかたがわかりません。しかし、メモリ操作エラーなどで落ちたときには、そのトレースはとれます(詳細はWindows(Win32)上でのMozillaのデバッグFAQを)。なので、あえてあやしそうなところに適当にポインタをいじってアクセス違反をおこしておとしてしまいます。そうすると、どこからなにがよばれているかの階層構造が見事とれるわけです。

それによって、ico ファイルを解析しているルーチンを見事つきとめ、あやしそうなコードをなおしてみると、どんぴしゃ!というわけで、パッチが見事かけたのでありました。

この Bug は本家では Dup(重複、Duplicate)がたくさんあったようで、bug-org 163874 もおちなくなりましたが、おちなくなっても画像がこわれる現象がでたので追求してみましたが、わたしはなんのやくにもたてないうちに本家のほうでパッチがだされて FIX されました。

Bug-JP 2745 の追求

これについては実質デバッグはしていません。

このバグはある時期以降に発生した regression です。なので、どのパッチが原因なのかは時間をみれば特定可能なはずです。

ひたすらいろんな次期のソースでビルドしまくるええ、何月何日何時のビルドまで発生しないで、何月何日何時のビルドから発生したかをしらべればよいのです。そのあいだのパッチが regression の原因です。範囲をせばめるのには二分検索をつかいましょう(あたりまえや!)

trunk で発生した場合は、ともかく trunk のソースを入手します(Tag の関係で Release のソースはつかわない方がよいでしょう)。

cvs では -d オプションをつかえば、過去のソースがとれます。ところが、すくなくとも Windows では、じかに cvs をたたいても、とれません。ここで make は引数をわたすことで cvs からひっぱってくることができることをおもいだしてください。

clinet.mk ファイルをよむと、make に引数 MOZ_CO_DATE をわたせばひっぱってこれることがかいてあります(ほかの引数も参考になるのでおぼえておきましょう)。make -f client.mk MOZ_CO_DATE="xxx"のようにしましょう。

あとは、ひたすら何月何日何時のビルドまで発生しないで、何月何日何時のビルドから発生したかをしらべればよいのです。

それがわかったら、bonsai と比較します。その時間にチェックインされたパッチをみればよいのです。あとは、cvs をかいさず、あやしいパッチをいれたビルドとそうでないビルドの動作を比較すればおわりです。

MOZ_CO_DATE の値は cvs にわたされるのとおなじ日付のフォーマットです。bonsai の時刻はあくまで bonsai のサーバの標準時(PST)です。なので、日本の Win の DOS 窓で、特別な環境設定をしないで MOZ_CO_DATE="2002-10-10 23:00" とわたした場合、bonsai でいうところの 2002/10/10 6:00時点のソースがとどきます。時差 17時間です(夏には夏時間で1時間差ができます。なので、PSTに環境変数をセットしてやるか、MOZ_CO_DATE="3/31/92 10:00:07 PST"のようにするのが幸せでしょう)。

どうも、Javaのバグだったようで、Java SDK 1.4.2β以降を使えばこの問題は発生しないようです。

Bug-JP 2885 の追求

Windows の ATOK10 以降/WXG4 で、確定アンドゥ(Ctrl+BS)がうまく動かないというもの。

どうも、ATOK が Ctrl + BS を押した時に送ってくるウィンドウメッセージが、MS-IME とは違うばかりか、Mozilla が想定もしない順序で飛んできているらしい(詳しくは後日書こう・・・)。

中野さんの努力で、なんとかなりました。でも ATOK 自体にバグがある疑いがぬぐえない・・・。

Bug-JP 3614 の追求

bug-org 232969

WinXP の 新スタートメニューにて、標準のブラウザにしたとき、スタートメニューのコンテクストメニュー設定に JLP などで non-ASCII を設定すると文字化けする問題。

OS はレジストリを参照しているらしいが、レジストリには SJIS to UTF8 変換の結果とおぼしきものが入っているらしいこと、JLP から文字列を取得する Mozilla のルーチンは内部で unicode に変換して持っているらしいことなどが、JLP フォーラムの各氏の分析で明らかになっていた。

私がソースを見たところ、最終的に Win のレジストリに書き込むルーチンにて、Native Code を渡す Windows の API に Unicode をそのまま渡していたことが判明。Native Code を入れてくれ、と bug-org に依頼。Windows の API には、内部で二種類あるものが多い。9x 系が non-unicode だったのに対して、NT系を unicode 対応したために、NT 系では、多くの API を 9x 互換の non-unicode 系の API と unicode 系 API を両方持っている。たとえば今回関係ある「RegQueryValueEx」という API これは、non-unicode な RegQueryValueExA と RegQueryValueExW と実は実体は二つあり、Win9x でビルドすると、RegQueryValueExA となり、 NT系で #define UNICODE を宣言してビルドすると、RegQueryValueExW となる。これは、実は RegQueryValueExA とか RegQueryValueExW とかフルネームではじめから呼び出せば、その通り呼ばれる。でも、W の API は 9x 系にはないので動かない。

私は、A に渡すので、Native codeing に、と言ったのだが、jshin が、「使い分けが必要」として、OS ごとに使い分けるパッチを書いた。実際、IME 処理などでは既に同じようなことをやっている。

後から他のところのソースを読んでみる限り、実際のところ、A の API だけを使っていて、使い分けさえすれば NT 系のみ unicode 対応にできる箇所は、Mozilla の中には非常にたくさんある。ここだけわざわざ両方にする必要があったのかはわからないが、Windows のレジストリ読み書きに関する汎用ルーチンだし、重要ということなのだろうか。

同様の問題はたくさんあるようで、A/W の使い分けにも限界があるので jshin(シン・ジョンシクという韓国のハッカー、2004年夏時点で l10n の細かいバグをそこら中で直している)が、MSLU のようなものを入れるぞと提案中。

Bug-JP 3621 の追求

Win9x にて、デフォルトのプリンタ名に日本語の文字が入っていると、file → printで「プリンタが見つかりません」と出てしまって印刷できない問題。

bug-org 167128がそれで、元々、NT系も含めて、日本語のプリンタ名自体が全然だめだったのもが、1.0.2に向けてパッチが一度入ったものの、まだ不具合が残っていた。

解析の結果、デフォルトのプリンタを取得するルーチンで、取得した SJISの 文字列に対して、ASCII を Unicode に変換するモジュールにかけていた。NT 系でうまくいっていたのはただの偶然。

はじめて自力のパッチがcheck-inされるかも。

まだ不完全だったので、中野さんがなんとかしてくれた。ただ、unicode 対応の課題が残っていて、そちらは MZLU 待ち。