@dmckee
まあ、それはコメント内には収まりませんが、ここにあります:
まず、正しい静的アナライザーを作成します。このコンテキストでの「正しい」とは、分析されたコードに疑わしい点がある場合に黙っていないことを意味するため、この段階では、未定義および未指定の動作を楽しく混同します。それらは両方とも重要なコードでは悪く、受け入れられません。当然のことながら、両方について警告します。
しかし、1 つのバグの可能性について警告するのは 1 回だけであり、また、アナライザーが他の (正しくない可能性がある) アナライザーと比較した場合に、ベンチマークで "精度" と "再現率" の観点から判断されることがわかっているため、 1 つの同じ問題について 2 回警告する... それが真のアラームか誤報か (どちらかはわかりません。どちらかはわかりません。そうしないと簡単すぎます)。
したがって、単一の警告を発行したい
*p = x;
y = *p;
は最初のステートメントで有効なポインターp
であるため、2 番目のステートメントでも有効なポインターであると見なすことができます。これを推測しないと、精度指標のスコアが下がります。
したがって、上記のコードで最初に警告するとすぐにそれが有効なポインターであると仮定するようにアナライザーに教えてp
、2 回目に警告しないようにします。より一般的には、すでに警告したことに対応する値 (および実行パス) を無視することを学びます。
次に、重要なコードを書いている人があまりいないことに気付き、最初の正しい分析の結果に基づいて、残りのコードについて別の軽量な分析を行います。たとえば、C プログラムのスライサーです。
そして、「彼ら」に伝えます。最初の分析によって発せられたすべての (おそらく、多くの場合、誤った) アラームを確認する必要はありません。スライスされたプログラムは、いずれもトリガーされない限り、元のプログラムと同じように動作します。スライサーは、「定義された」実行パスのスライス基準と同等のプログラムを生成します。
そして、ユーザーは喜んでアラームを無視し、スライサーを使用します。
そして、おそらく誤解があることに気づきます。たとえば、ほとんどの実装memmove
(オーバーラップ ブロックを処理するもの) は、実際には、同じブロックを指していないポインターで呼び出されると、未指定の動作を呼び出します (同じブロックを指していないアドレスを比較します)。また、アナライザーは両方の実行パスを無視します。どちらも指定されていないためですが、実際には両方の実行パスは同等であり、すべて問題ありません。
したがって、アラームの意味について誤解があってはなりません。アラームを無視するつもりなら、紛れもない未定義の動作だけを除外する必要があります。
そして、これが、未指定の動作と未定義の動作を区別することに強い関心を持つようになる方法です。後者を無視したとしても、誰もあなたを責めることはできません。しかし、プログラマーは前者は何も考えずに書いてしまいますし、あなたのスライサーがプログラムの「間違った振る舞い」を排除していると言っても、彼らは気にしないでしょう。
そして、これは間違いなくコメントに収まらない話の終わりです. ここまで読んでくださった方、申し訳ありません。