PVS-Studio静的アナライザーに独自の診断ルールを追加する方法をよく聞かれます。 そして、これを行うのは非常に簡単であると常に答えます。「私たちに手紙を書くだけで、このルールをアナライザに追加します。」 新しいルールを追加するためのこのようなインターフェイスは、ユーザーにとって便利です。 これは最良かつ最も便利なインターフェースです。 自分で仕事をするのは思ったほど簡単ではありません。 注では、「この単純なルールを追加した」という概念の背後に隠れている氷山の水中部分を示します。
すぐにきれいにしましょう。 PVS-Studioでは、ユーザーが独自のルールを作成するメカニズムはありません。 これはまず第一に、アーキテクチャ上の制限です。 そして、一部のユーザーは動揺するかもしれません。 ただし、実際には、そのようなユーザーは自分が望むものを理解していません。 人生では、新しいルールを追加するプロセスは非常に複雑だからです。
たとえば、ルールV536があります。使用される定数値は8進数形式で表されることに注意してください(「8進数定数の正しい使用を確認する」)。 Miranda IMで次のようなエラーを検出するように設計されています。
静的const struct _tag_cpltbl { 符号なしcp; const char * mimecp; } cptbl [] = { {037、 "IBM037"}、// IBM EBCDIC US-カナダ {437、 "IBM437"}、//米国OEM {500、 "IBM500"}、// IBM EBCDIC International {708、 "ASMO-708"}、//アラビア語(ASMO 708) ... }
037はC ++ルールに従って8進表記であるため、10進31であることが判明しましたが、アライメントのために37の代わりに037と表示されます。 エラーの診断は非常に簡単ですよね? 実際、定数を探し、0で始まるかどうかを確認して、診断メッセージを発行します。 このような診断ルールは1時間で実装できます。 そして、静的アナライザー(プログラミングの専門家ですが、このようなツールの開発は初めてです)のユーザーは、理論的にはこのようなルールを実装する準備ができています。
ただし、彼はこれを行うことができません。 むしろ、結果は判明しますが、彼は多数の誤検知のために結果に満足しません。
私たち(PVS-Studio開発者)は次のことを行います。 ルールを実装する前に、まずユニットテストを作成します。このテストでは、ルールをトリガーする行を特別な方法でマークし、ルールが何も生成しないユニットテストの行を残します。 次に、診断用のコードの最初のバージョンが作成されます。 この新しいルール用に作成された単体テストの合格を達成した後、すでに完全な単体テストを実行します。 結局、新しいルールは何かを壊す可能性があります。 完全な単体テストには数十分かかります。 もちろん、最初に「何も壊すことができない」ことは常に可能とはほど遠いため、ユニットテストが完全にパスするまで反復が繰り返されます。
単体テストの後、次のステップは実際のプロジェクトで起動することです。 テストベースには約70のプロジェクトがあります(2011年)。 これらはよく知られたものであり、アナライザーをテストするオープンソースプロジェクトではありません。 Visual Studioでプロジェクトを開き、アナライザーを起動し、ログを保存し、それを標準と比較し、違い(表示されなくなったメッセージ、追加されたメッセージ、変更されたメッセージ)を表示する独自の自作ランチャーがあります。 Visual Studio 2005のすべてのプロジェクトの1つの実行は、4つのコアと8ギガバイトのメモリを搭載したマシンで4時間続きます(分析は並行して行われます)。 分析の結果によれば、新しいルールの実装の結果がわかります。 通常、分析が完了するのを待たずに違いを調べ始めます。「すべてが壊れている」ことがすぐに明らかになることがあります。 ただし、すべてが正常に機能し、何も壊れていない場合でも、多くの場合、テストは早く停止します。 この理由は誤検知です。 診断ルールの正の数が多すぎる場合、ルールに例外が表示され始めます。
誤った8進数の検索に戻りましょう-ルールV536。 いくつかの例外があります。 診断が発行されない状況は次のとおりです。
- 定数値は8未満です。
- 番号は#defineを介して宣言されます。
- 1つのブロックで、char型の0以外の2つ以上の8進数(ルールは2回以上機能しました)。
- この番号は、関数の引数として使用されます:_open、mknod、open、wxMkdir、wxFileName :: Mkdir、wxFileName :: AppendDir、chmod。
- これは数字のネストされたブロックです。 一番上のものだけをチェックします。 例:{{090}、{091}、{092}、{093}}。
- この番号は<= 0777であり、単語が存在するステートメントの一部です:ファイル、ファイル。
- 数値は関数の引数であり、そのパラメータの1つに文字列「%o」が含まれています。
実際のプロジェクトで起動する前に例外を予測することは常に可能とは限りません。 したがって、「例外-テスト実行-結果の分析」の反復を何度も繰り返すことができます。
次に、すべての例外が実装され、誤検知の数が適切な場合、テスト結果(検出されたエラーの保存されたログファイル)が参照結果として宣言されます。 その後、同じテストがVisual Studioの他のバージョンに対して実行されます。 現在(2011年)、Visual Studio 2005/2008/2010の3つのバージョンをサポートしています。それらのテストは4 / 4.5 / 5時間実行され、合計14〜15時間になります。 Visual Studioの別のバージョンで実行した結果によると、Visual Studioのバージョンに応じて、同じコードに対して異なる数の診断メッセージが発行される場合があります。 これは通常、さまざまなSDKのヘッダーファイルの違いが原因です。 Visual Studioのすべてのバージョンでテストを実行しても同じ結果が得られるように、違いを排除しようとしています。
これらの退屈なテストをすべて実行することがなぜそれほど重要なのでしょうか? 本当に偽陽性のためだけですか? いいえ、誤検知だけではありません。 重要な点は、ルールを実装するときに、考えられるすべてのタイプの構造を考慮してルールを記述し、正しく機能し、さらにアナライザーがクラッシュしないようにすることは非常に難しいということです。 これは、この膨大な量のテストがすべて必要なものです!
奇妙なデザインとは何ですか? いくつか例を挙げましょう。
たとえば、次のように変数を宣言できることをご存知ですか?
int const unsigned static a22 = 0;
__int64が変数名であることをご存知ですか?
int __identifier(__ int64);
スイッチの中括弧がオプションであることを知っていますか?
スイッチ(0) if(X)Foo();
コードで同様の構造を使用していない場合でも、使用されるライブラリに含まれています。
最後に、すべてのテストに合格すると、ドキュメントを取得できます。 診断ルールごとに、ロシア語と英語の証明書を作成します。 英語への翻訳にも時間がかかります。 これで(コードのデバッグ、テストの合格、ドキュメントの作成)、ルールはPVS-Studioの次のリリースに移行します。
そのため、新しい診断ルールの開発サイクルは、次のように簡単に表すことができます。
- 新しいルールのアイデア。 発明するか、ユーザーにプロンプトを表示するか、どこかで覗き見します。
- ルールの策定。
- ルールの実装。
- あらゆる種類のテスト。
- 結果の分析。 オプションは次のとおりです。
- 規則の文言の確定、例外の導入、第2項への移行
- ルールの実装は確立されていると見なされ、ドキュメントを作成および翻訳できます。
次に、ユーザーにルールを追加する方法の質問に戻ります。 ご覧のとおり、2つの簡単な理由から、自分で実行するのは困難です。 ユーザーには、成功した例外を思い付くのに十分な資格がなく、ルールをテストで進めるための適切なテストベースがありません。
「なぜ、有名で有名な静的アナライザーの中に、独自のカスタムルールを設定する方法があるのですか?」これができないのではないでしょうか? 部分的にはい。 ただし、独自のルールを設定するメカニズムのみが、「競合他社と比較するためのマトリックス」をコンパイルするという1つの単純な目的に役立ちます。
それで、読者は、PVS-Studioではカスタムルールを作成することは決してできないでしょうか? いつか、これを実装するのに十分な強度を持ち、比較マトリックスで負けることはありません:-)。 それまでは、このテキストへのリンクを提供する新しいルールを作成するすべての人に、「カスタムルールを追加するのに最適なインターフェイスがあります。メールでお問い合わせください!」