オプションを一行追加しといて #41

公開日: 2012-08-19


ふたたび Chromium OS の話。出先にいるエンジニアから緊急のバグが振ってきた。いわく、<canvas> タグのGPUアクセラレーションが有効だと描画に問題が出るから、リリースする前に至急、アクセラレーションを無効にする必要がある。--disable-accelerated-2d-canvas というオプションをブラウザの起動スクリプトに追加するだけだからやっといて、とのこと。

了解、すぐやっておきますよ、と返事して、パッチを作った。コードレビューを済ませて(といっても一行、オプションを加えるだけだけど)、さくっと commit queue (ビルドしてテストが通ったらサブミットしてくれるシステム)に投げて、一丁あがり!

と思いきや、まったく関係なさそうなテストがいくつか落ちて commit queue にパッチを拒絶されてしまった。関係のないテストが不安定(flaky)で落ちることはたまにあるから、特に気にせず、 commit queue にもう一度投げてみた。結果は同じで、同じテストが落ちている。でもどうみても関係なさそうなんだけど。

IRCで相談してみると、昨日ログイン周りの部分が何かバグっていたので、その問題かもしれない、とのこと。確かにログインの部分がバグっていたら、こういうテストは落ちても不思議ではない。というわけで、ふたたび commit queue に投げてみた。が、結果は同じで同じテストが同じように落ちている。

ここまできて、ようやく、自分の変更が原因なんじゃないかと疑いはじめた。落ちているテストをみると、どうもゲストモードで動かすテストがタイムアウトで落ちている。ということは、ログインかログアウトのどちらかで止まっているのであろう。

しかし原因は見当がつかない。ログインにしてもログアウトにしても <canvas> タグなど関係ないからだ。しかも、ゲストモードのときだけ問題が起きるのはますます謎だ。

こうして途方にくれていると、頼りになることで定評のある同僚がどこからともなくチャットに現れて、お前の変更は特定のデバイスだけでテストが落ちているようだな。他のデバイスでは問題なく通っているよ、とヒントをくれた。

いやー、いきなり現れてヒントをくれるとはありがたい。でもなんで特定のデバイスだけなの?ログインもログアウトも全デバイスで共通の挙動なんですけど。

仕方がないので、問題のデバイスを手に入れてきて、自分の変更を試してみることにした。 --disable-accelerated-2d-canvas を足して、ゲストモードでログインして、、うわ!ゲストモードでログインしたら激しく壊れている。

ブラウザはちゃんと表示されてちゃんと動くけど、画面下部の launcher というUIがまったく表示されない上、 ログアウトのショートカットキーも使えない。これはおかしい!

どうも launcher を含めたデスクトップ環境(Aura Shell を略して ash と呼ばれている)が完全に消えてしまっているようだ。ash に一番詳しいエンジニアのところに行って見せてみると、こんなの見たことがない、原因もさっぱりわからぬ、とのこと。

で、別のエンジニアにみせると、もしかしたら --disable-accelerated-2d-canvas というオプションに副作用があって GPUの他の部分の挙動も変えちゃっているんじゃないか?との仮説をくれた。

たしかに副作用というのはありえるかも、ということで GPU に詳しい人のところに持って行くと、心当たりはないとのこと。で、コマンドラインが長すぎるのが原因かもしれないから、ちょっと順番を変えてみようといって、順序をいじっていたが、特に変化はなし。うーむ、こまった。

さらに他のエンジニアにあたってみると、ゲストモードに切り替える処理ではブラウザのプロセスを立ち上げ直す(おそらく、メモリ上のデータを全部捨てるため)という不思議なことをやっているから、その辺を調べてみたらいいんじゃないかとのこと。確かにこの辺は実に怪しい。

といったあたりで時間切れ。残っていた同僚に、時間があったら調べといてと言い残して帰ることにした。

その後、夜になってメールをチェックしていると、件の同僚から、途中まで調べて大体見当がついた、というチャットが飛んできた。ゲストモードに切り替わった後、なぜかコマンドラインの処理がおかしくなっているので、そこを調べるべし、俺は明日から休暇だ、とのこと。

たしかにそこはあやしい。。ん、ということは、もしかしると、GPUの彼が言ってたみたいに、コマンドラインが長すぎるのが問題なんじゃないの?

いやでも特定のデバイスだけで問題が起きるのは変だ。コマンドラインはどのデバイスでも同じはず、と思って、起動スクリプトをみてみると、そんなことはなく、ハードウェアのコンフィギュレーションに応じてコマンドラインが足されたりしている。ここにきて、かなり確信が高まってきた。

といっても、手元ではテストできるデバイスはないので、時差のあるオフィスにいる同僚にチャットで頼んでみると、ビンゴ。 --disable-accelerated-2d-canvas を足しても、他のオプションを消せば問題なく動くとのこと。とほほ。コマンドラインの長さが原因とは。

というわけで、とりあえずこの問題を直すには不要なコマンドオプションを削ればOK。使っていないオプションもいくつかあるだろうから、とりあえずそれらを削れば当座はしのげるはず。

なんだけど、まだ腑に落ちない。コマンドラインの長さはたしかカーネルの設定で決まっていて、通常は問題にならないくらい十分に長いはず。

それに引っかかるのほどコマンドラインは長くないだろうと思いゲストモードの実装をみると、ややこしいことをやっている。ブラウザが自分自身を立ち上げ直すのではなく、いったん、 session manager という別のプロセスにコマンドラインなどの情報を IPCでメッセージを送って、そっちから立ち上げ直している。ややこしいけど、なにか理由があってのことなのだろう。

で、その session manager を見ると、非常に残念なコードが目に入った。

const int kMaxArgumentsSize = 1024;

がーん。ようするに、これなのだ。コマンドラインの長さがこの値を超えると、コマンドオプションはすべて消えてしまい、ゲストモードのブラウザは一切のコマンドラインオプションなしで立ち上がる。その結果、必要なオプションが不足してデスクトップ環境が消えてしまうのだ。

コードをよくみると、文字列処理を単純化するためにこの定数が使われている様子。本来はこんな制限をかける必要はまったくないはずで、正しく直すにはこの定数をとっぱらって、可変長の文字列にすることなんだけど、リリース前に至急直す必要があるので下手にいじって壊したら困る。残念な気分になりつつも、定数を適当に大きくすることでごまかすことにした。

というわけで、世にも奇妙なバグの原因は非常に残念なものであった。結局、一行を加えるだけの簡単な変更のはずが、えらい時間を食ってしまった。

ちなみに、ソフトウェア開発における私の信念は Nothing is easy (簡単なことなどない)というもので、これを心にとめておくと、物事がスムーズに進まなかったときも、あまりがっかりしたりイライラしたりしないですむ。今回もまさにそんな感じの事件であった。

Satoru Takabayashi