コンパイラとヒヤリハット

とある記事を読んでいたら突然キャッチィなタイトルが脳内に去来したので書いてみる。


よく企業では安全対策などの現場で「ヒヤリハット」という標語が叫ばれている。オヤジギャグのような単語だが、大きな問題の影には、日頃「ヒヤリ」としたり「ハット」するようなたくさんの小さな問題が潜んでいるというものだ。
典型として、1:29:300という比率(1件の重大事故の背景に29件の軽症事故と300件の事故未遂のヒヤリハット事例)があるといわれている。


話は変わって、今回 MS08-014で修正されたExcel脆弱性は、「スタック変数の未初期化問題」だったそうだ(Security Vulnerability Research & Defense : MS08-014 : The Case of the Uninitialized Stack Variable Vulnerability)。これは比較的良くありがちなミスだが、ローカル変数を初期化しないで使ってしまったというものだ。
ローカル変数はx86システム上ではスタック上に確保されるので、直前までのコンテキストの実行状態によりスタックの値がどうなっているか、など誰も知りようがないし、まして保証できない。たまたま 00h になっていることもあるだろうし、或いは誰かがスタックを深くまで使っていれば、以前使った何らかのデータや、あるいはリターンアドレス、レジスタの退避値など予期しないデータが入っている可能性がある。


これを勘違いして、「いつも 00h で初期化されているに決まっている」と勝手な思い込みをする人や、頭では理解していてもついうっかり初期化を忘れたままにしてしまうことがある。
この場合はスタックに入っている値によって思わぬ動作をしてしまう。場合によっては一般保護例外でプログラムが強制終了してしまう場合もあるだろうし、データファイルにでたらめな値を書いて壊してしまったり、あるいは運がよければ単にエラーメッセージを出して期待通りの動作をしないだけだ。


仕事柄、たまにプログラムに関するユーザーサポートみたいなことをすることもあるが、たまにこのあたりの理屈が理解できないで理不尽なクレームをつけてくる客もいる。
曰く、A社のデバイスBではちゃんと動くプログラムが弊社のデバイスでは正しく動かないという。やり取りをしているうちに、ポインタとして使っているローカル変数を初期化せずに使っているためにメモリアクセス違反(不正アドレス)を起こしていることがわかった。それに対して「おたくのデバイスではなんでメモリが初期化されてないのか。おかしいじゃないか」などとクレームをつけてくるのは全くもってお門違いであり、馬鹿げている。


ただし、たいていの場合この問題はコンパイラが検出してビルド時にwarningメッセージを表示してくれる。プログラマがwarningと侮って無視さえしなければ通常は気付いて回避することができる。
しかし人によってはFatal errorでないのだから無視してもいいだろう、などといってwarningは無視してしまうこともあるのだろう。おそらく今回のExcelの問題もこういう人的原因もあるに違いない。


ここで冒頭のヒヤリハットが関係してくる。
なんだか構造が似ていると思ったのだ。
「1つのインシデント(流出バグ)に対して、29個のwarningと、300個の検出されない軽度のバグが潜んでいる」というのはどうだろうか。実際の数字は違っているだろうが、ピラミッド構造で説明できるのは間違いないのではなかろうかと思う。


warningと侮るなかれ、warningといえど検出されたからには何かしらの問題があるのだ。最終リリースの前にwarningであれど0個になるように対応すべきだ。warningがでるということはそれだけプログラミングの脇が甘いといえる。それは即ち目に見えない(コンパイラが検出できない)仕様バグや論理バグ、ポカミスなどが潜んでいる可能性があると考えて、改めて仕様やソースコードをしっかりレビューし直しててみるべきだろう。


またコンパイラオプション「/W4」を指定すれば、warningレベルを最高にして、些細なwarningでも検出するようになる。当然ながらノイズ(偽陽性warning)も増えてしまうが、より確実さを求めるならやってみるべきだろう。ほとんどのwarningは適切な書き方に改めれば解決する。問題はないことが確実にわかっているのにどうしてもwarningが出てしまう場合でも#pragma warningを使えば最低限の抑制はできる(醜いやり方なのでおすすめはしないが)。