説明を誤って理解するとエラーが見落とされ、最悪の場合には誤検知に変えられてしまう。
我々が過去7年間に採用してきた正しいアプローチでは、ビルドのプロセスを開始し、呼び出されたシステムコールをひとつひとつ封じる。その結果、呼び出された実行ファイル、そのコマンドライン、それらが実行されるディレクトリ、コンパイラのバージョン(コンパイラとそのバグの回避策に必要)など、チェックに必要なすべてのものが見えてくる。このようなコントロールにより、すべてのソースコードの獲得と正確なチェックが容易になり、言語の「方言」をファイル単位で自動的に変更できるほどになる。
当社のツールを起動するには、ビルドコマンドを引数として呼び出すだけでよい。
cov-build<build command>
我々はこのアプローチを安全度が高いものだと思っていた。しかし残念なことに、賢明な読者ならお分かりのとおり、これにはコマンドプロンプトが必要だ。これを大手顧客に導入した直後、我々は相手先を訪問したが、そこは大企業だったので高い専門性を備えたビルドエンジニアがいた。下記の会話はそのエンジニアとの間で交わされたものだ。
御社のツールは、どうやって実行すればいいんでしょうか?
簡単ですよ。ビルドコマンドの前に「cov-build」とタイプしてください。
ビルドコマンドですって? 私は、この「GUI」ボタンを押すだけなんですが。
社会vs.技術。変えることができない社会的制約は、それがいかに破綻していようと、みっともない回避策を取らなくてはならない。よくある例は次のようなものだ。Windows上でのビルド埋め込みには、デバッガのコンパイラの実行が必要だ。残念なことに、これを行うと非常に普及しているWindows C++コンパイラのVisual Studio C++ .NET 2003が、奇妙なエラーメッセージとともに途中で終了してしまう。
ストレスを感じながら調査した結果、コンパイラにuse-after-free(解放後使用)のバグがあり、コードがMicrosoft特有のC言語拡張(#を使った命令のある種の起動)を使用したときにヒットすることが分かった。コンパイラは通常の使用では問題なく作動する。解放されたメモリを読み込むとき、オリジナルのコンテンツはまだメモリ内にあるため、すべてが正常に機能する。しかしデバッガと連動して稼働するとき、コンパイラは解放されたメモリコンテンツを解放コールのたびに不要データの値に設定する「debug malloc」を使用するよう切り替わる。後続の読み取りではこの値が返され、コンパイラは致命的エラーによりクラッシュする。つむじ曲がりの読者なら、おそらく「解決策」は想像がつくだろう。
法則:解析できないコードはチェックできない。コードを徹底的にチェックするには、そのコードのセマンティクスを細部まで理解しなくてはならない。一番基本的な要求事項は、解析を行うことだ。解析すれば問題は解決するとされる。ところがこの見方は甘いとしかいいようがなく、プログラム言語などというものが存在するという、広く信じられた神話に根差したものである。
―――そもそも、C言語は存在しない。Java、C++、C#もしかり。概念としての言語は存在するにしても、そしてそれを定義していると称される山のような書類(標準)があるにしても、標準はコンパイラではない。人々はどの言語でコードを書くのだろうか? コンパイラが受け付ける文字列で、である。そのうえ、彼らはコンパイルと保証を同一視する。コンパイラが拒否しないファイルは、そのコンテンツがコンピュータ言語学者からみると明らかに不正なものであっても「Cコード」として認定される。Cのフロントエンドを含むバグ検出ツールがこのような不正な非Cコードを与えられると拒絶する。このような問題がツールの問題となった。
問題をさらに悪化させたのは、ツールの実行に責任を持つ人は、チェック対象のコードがツールを不安定にした場合に責められる人とは別人であることが多いということだ(この人物は、分析されたソースコードやツールの作動原理を理解していないことが多い)。とりわけ、当社のツールは夜間ビルドの一環として実行されることが多いため、そのプロセスを管理するビルドエンジニアがツールの正常稼働に責任を持つことがしばしばある。多くのビルドエンジニアが考える成功の明確な基準とは「すべてのツールが正常な終了コードで処理を終了する」というものだ。彼らはCoverityのツールを、処理しなくてはいけない事柄のリストにある一業務にすぎないと捉えている。「正式」なコンパイラが受け入れたのにツールが解析エラーで拒否したコードの修正を喜んで行う人が、どれだけいるだろう。一般的に、こうした関心のなさが、彼らが責任を持つツールのあらゆる側面に対する関心のなさにつながっている。
コンパイラの多く、いやおそらくすべては標準から逸脱している。コンパイラにはバグがあり、非常に旧式であったり、プログラミング言語の仕様(C++だけではない)を誤解している人が書いていたりするし、多数の拡張もある。こうした逸脱のせいで、標準に則っていないコードが出てくる。もしコンパイラが構成概念Xを受け入れるなら、それを理解するプログラマーとコードが与えられれば、しまいにはXは拒否されずにタイプされるようになり、コードベースに収まってしまう。ところが静的ツールは不都合なことに、それを解析エラーとして警告する。
重要なマーケットには逸脱コードがあふれているため、ツールはそれを単に無視するわけにはいかない。たとえば、ある巨大ソフトウェア企業はかつて適合性を競争上のデメリットと考えていた。なぜならその企業の製品の代替品となるツールを他社が作ることを許してしまうからだ。組み込みソフトウェア企業も、その顧客がバグを嫌悪することを考えれば、ツールの素晴らしい売り込み先だ。ユーザーは自動車(あるいはそれがトースターであっても)の故障を嫌がる。残念なことに、そうしたシステムにおけるスペースの制約と、ハードウェアとの強い結び付きにより、コンパイラ拡張は、熱烈に支持、利用されている。