Shiro(2011/09/16 02:28:53 PDT):ハードなバグに関する話って読んでてとてもおもしろいのだけれど、 いざ事例を探そうとすると思うように探せないので、何となくまとめておこう。 好きなように足してください。自分で書いてリンクするのも歓迎。 (2017/05/06 17:40:34 UTC: 新しい記事を前に足してゆくように変更)

ハードウェアバグ。 抽象化が漏れる事例として非常に興味深い。

ゲームで性能を出すために、L2キャッシュをバイパスするプリフェッチ命令を追加した。 しかしL2キャッシュにはメモリのコヒーレンシを保つ機能もあり、 バイパスすると一貫性が保証できなくなる。 実際、うっかり他のプロセッサが書き込みを行うアドレスと同じキャッシュラインに乗るデータを プリフェッチしてしまうと、その部分がCPU間で食い違いクラッシュした。

ところが、そのプリフェッチ命令を使うコードをスキップするようにランタイムフラグを変えても、 同様のクラッシュが起きる。メモリダンプをいくら眺めても原因がわからない。

犯人は分岐予測による投機実行だった。分岐予測ミスで 本来実行されないはずのプリフェッチ命令が実行されてしまうことがある。 実行がキャンセルされても、キャッシュの状態は巻き戻されないので、 そのインストラクションがたとえ実行されないパスであってもコード中に存在するだけで、 効果を発揮してしまっていたのだ。

投機実行の正当性の前提は、投機実行されるコードが副作用を持たないことだ。 しかしこの「副作用」の範囲はどこまでか。 通常考えるのはCPUのISAレベルで扱う、レジスタやメモリの状態だ。 キャッシュはその状態に対して透過的に動作するはずで、論理的な動作モデルとは分離されているはずだった。 その抽象化の壁が壊れる事例のひとつ。

本人の体験ではないけれど、おもしろいので。オーバーフローに起因するバグ2題。 初代CivilizationのNuclear Gandhiと、Ariane 5ロケット。

メモリリークを追いかける話。新しいバージョンのサーバをデプロイしたら数百MBしか 消費しないはずのプロセスがGB単位でがんがんメモリを増やしてこける。

最適化ってのはその時点での制約条件に対する特殊化でもあるんで、 条件が変わると逆にお荷物になり得るんだよな。でもそれを見直すのは難しい。 広く使われて概ね動いている実績があるほど、動いてるコードには触るな、になりがちだし。

それはそれとして原因を追ってく過程が詳細でおもしろかった。こっちも行き止まり、 あっちも行き止まり、途方に暮れた時にふと壁の隙間から光が漏れてるのに気づく、って展開、 よくあるよね。

特定のアーキテクチャでMonoを使ってるソフトがランダムにSIGILLで落ちる。 でもデバッガで見ても該当アドレスのインストラクションは正しい。 インストラクションキャッシュのフラッシュのコードを疑うが、 調べてみても変なことはやっていない。何故?

非対称マルチコアプロセッサでは、ランタイムにプロセッサ特性を問い合わせても それが実行されるコアによって帰ってくるパラメータが違う、というのが犯人なんだけど、 この可能性を思いつくこと自体が難しいだろうなあ。

バグの症状からパターンを見つけてそれを解決につなげる過程が見事。

localhostへのtcp接続がたまにtimeoutする。サーバのrecv queueは空なので サーバが取りこぼしてるわけではない。lo経由だからどこかでパケットが落ちてる わけでもない。なのにSYNパケットの返事が来ない。何故?

原因を突き止める経緯が参考になる。種明かしをすると、サーバがソケットの後処理を 忘れてて、クライアントがいなくなった後でもソケットがCLOSE_WAITのままになっていた。 そこで新たなクライアントがたまたま同じポート番号を使って接続要求を出すと、 サーバのカーネルは以前のクライアントから場違いなSYNパケットが送られてきたと思って 無視してた、というわけ。

めっちゃ基本的な関数にもバグが残ってることがある。この場合、特殊プラットフォームのみ 使われるインラインアセンブラのバグだけれど、gccのレジスタ指定をミスってて まだ使うレジスタが上書きされてたというもの このミスは自分も経験あるけど、ソースだけをいくら眺めてもわからないんだよね。

medium.comのオンラインエディタで、ポーランド語のŚだけが何故か入力できない、というバグ。

技術的に複雑な話ではなく、むしろ原因は歴史的あるいは文化的なものだ。

バグは技術と文化の界面に生じるものなのかもしれない。 コードが変わらなくても、コードを取り巻く環境が変わればかつての仕様は新たなバグになり得る。

組み込みLinuxデバイスが時々死ぬ問題を追いかける話。現象にも結論にも派手さはないけれど、 追いかける過程が丁寧に書かれているのが参考になる。

ガウス分布を生成するコードが非常に稀にクラッシュするというバグレポートを受け取った。 しかしその部分のコードは世界中で使われているRANLIBから持ってきたもの。 稀とはいえこれまで問題になっていないのは何故?

調べてみると、サンプリング部分のコードは共通だけど、乱数発生器だけ独自のものに 差し替えていた。乱数発生器は0から1の間に一様分布する実数を生成するものだが、 これが正確な0を返した場合にクラッシュする、という問題がRANLIBの元のコードにあることを発見。 しかし、そもそも閉区間の発生器を使ったのは、RANLIBのコードの元になった1973年の 論文でそう書いてあるからだ。

更なる調査によって判明した事実: 元論文に閉区間と開区間を取り違えるバグがあった。しかしその実装でたまたま他のみんなが(論文に反して)開区間の発生器を使っていたため、そのバグは41年間表面化しなかった。

あるバグが他のバグによって隠されるということは時々あるが、 これだけ使い込まれたコードにも潜んでいることがあるというのは興味深い。著者はこれを 隠された遺伝的変異に喩えている。

LinuxでSIPアプライアンスを作っている人。 顧客のところで「インタフェースが死んで、物理的に電源をon/offしないと回復しない」という トラブルが散発。手元ではどうしても再現しない。壊れたアプライアンスを送ってもらっても、 手元で火を入れてテストするとちゃんと動く。

結局NICのファームウェアのバグとわかるんだけれど、 まず問題を手元で再現する手がかりを見つけるまで数ヶ月。 そこからさらに絞り込んで、最終的な再現条件を見つけるまでがまた大変。 デバッグに銀色の弾丸なし、地道な調査あるのみだなあ。

ロンドンからモントリオールへのssh転送が時々失敗する。 パケットダンプから原因を追いかけ、失敗しているノードの特定まで。

見どころは、インターネット上の自分では触れないノードのどこかの機器が失敗している という状況で、自分から触れる道具を駆使して原因を追い詰めてゆくところ。

向井さんのG+ポストより。

valgrindがリークをレポートした。でもデストラクタで開放してるのに…コードを良く見たらデストラクタに至る前にSIGTERMで終了してた。落着? いや、でも他にもデストラクタが呼ばれてないデータはたくさんあるのにvalgrindはレポートしてないよ?

手がかりが見つかったと思ったら違ってて、また新たな手がかりが見つかって…と二転三転するミステリのようなバグ譚。

なぜか無関係なパッチでMacのビルドだけが壊れる。はじめはMacのビルド環境がflakyなだけかと疑ったが……。

(高林さんのポスト経由)。 Windows上での謎のクラッシュを追い詰める。デバッガから取れる情報はあまり役に立たず、 上のOSXのケースと違ってOSの中身もいじれない、という状況で、 instrumentationを仕込んで原因を絞って行く話。

(鵜飼さんのGoogle+のポスト経由)。 OSXのChromeのリソースリーク (MachカーネルがIPCに使うポートを食いつぶす) を追い詰める。 ストーリーは淡々と語られてるけど、技術的なディテイルが詳しく語られてて参考になる。 既存のカーネルインタフェースでは犯人をつきとめるのに必要な情報が得られないので、 即席のカーネル拡張を書いてしまうあたり、著者の並ならぬ体力を感じさせてくれる話である。

効率化のためのちょっとした変更で、テーブル拡張の度に頻繁に衝突が起きるようになり 大幅に遅くなったという話。局所的だと思ってやった変更が思わぬ干渉を起こすって 経験はあるなあ。機能テストにはひっかからないのが厄介。

ハードウェアのバグ。バグ自体は特異なものじゃないけれど、printfさえ使えない状況で どうやってバグを絞り込んだかが面白い。via Radium Software

データベースサーバが謎のトラブル。しかし、 隣の倉庫に配送車が到着したときだけ、魔法のようにサーバが正常に戻るのだ…

物理的に500マイル以上離れたサイトにメールが届かない、というユーザからのクレーム。 emailの配送に物理的距離は関係ないだろう、何かの間違いでは、と思ったが事実だった。

Kernel, gcc, glibcが複雑に絡み合ったバグの追跡。

テストを足したら、別のテストがメモリを食いまくって落ちる。 だが、落ちる時点では、足したテストはまだ実行されていないのだ。

教訓: 隠された状態に注意せよ

I just fixed a 20-year old bug… that I wrote, and is in daily use by a few million people…