PVS-Studio Static Code Analyzer の概要

C++Russia カンファレンスの 1 つで、PVS-Studio コード アナライザーを開発しているチームと知り合いになりました。では、そちらに譲りたいと思います。彼らはこの素晴らしいツールの簡単な概要を作成し、いくつかの便利なリンクを提供します.さらに、彼らはあなたにささやかなボーナスを提供すると約束しました。

こんにちは、みんな。ゲスト投稿を許可してくれた Rainer Grimm に感謝し、始めましょう。

静的アナライザーが発行するメッセージは、コンパイラーの警告に似ています。違いは、静的アナライザーはコンパイラーと同じような厳しいパフォーマンス制限を受けないことです。コードの最適化を目的としたものではありません。アナライザーは、より多くのメモリを使用してより長く動作できるため、より深くより高度なエラー検出アルゴリズムを使用できます。たとえば、次のコードでは、関数の相互接続を追跡し、メモリ リークと null ポインターの逆参照を検出できます。

int *GetPtr()
{
 int *a = (rand() % 2) ? new int : nullptr;
 return a;
}

void foo()
{
 int *p = GetPtr();
 *p = 123; // potential null pointer dereference
} // memory leak

これらのエラーは、PVS-Studio アナライザーによって検出されます:

  • V522 [CWE-690] 潜在的な null ポインタ 'p' の逆参照がある可能性があります。 test.cpp 35
  • V773 [CWE-401] 'p' ポインターの可視範囲が、メモリを解放せずに終了しました。メモリ リークの可能性があります。 test.cpp 36

PVS-Studio は B2B 製品として位置付けられていますが、無料で使用できるオプションがいくつかあります。多くのオープン プロジェクト開発者が無料で使用できます。さらに興味深いことに、小規模でクローズドな商用プロジェクトには無料のオプションがあります。これを取得するには、コードに特別なコメントを追加する必要があります。詳しくは、「無料の PVS-Studio ライセンスを取得する方法」をご覧ください。

商用コードでアナライザーを試す自然な方法は、試用版を入手することです。読者に約束されたボーナスがここにあります。ハッシュタグ #modernescpp 付き リクエスト フォームでは、ライセンス キーは 1 週間ではなく 1 か月間生成されます。

次の質問が発生する可能性があります。これはすべて意味がありますか?今日のコンパイラは、多くの潜在的なバグを見つけるのに非常に優れており、急速に開発されています。

上記の質問に戻ると、静的アナライザーを試すことは間違いなく理にかなっています。第 1 に、PVS-Studio チームも怠け者ではなく、欠陥を検出するためのアルゴリズムの開発に非常に積極的に取り組んでいます。これにより、十分にテストされたコンパイラでも PVS-Studio が検出できるエラーに関する記事を毎年投稿できます。

  • 2011 年の LLVM チェック
  • 2012 年の LLVM チェック
  • 2016 年の GCC チェック
  • 2016 年の LLVM チェック
  • 2019 年の LLVM チェック

次に、PVS-Studio はさまざまなサードパーティ ソリューションと統合され、興味深い補助サブシステムを備えています。これらのサブシステムの 1 つを使用すると、大規模なレガシー プロジェクトにアナライザーをシームレスに実装できます。一般的な考え方は次のとおりです。チームは大規模なコードベースでアナライザーを実行し、多くの警告を受け取ります。プロジェクトが存続している場合、重大なバグは何らかの形でより費用のかかる方法で修正されています。アナライザーが検出したものはすべて技術的負債と見なすことができ、すぐに排除しようとするのは非現実的です。

PVS-Studio に、これまでのところこれらすべての警告を無関係と見なし (技術的負債を後で延期するため)、それらを表示しないように指示できます。アナライザーは、重要でないエラーに関する情報を格納する特別なファイルを作成します。今後、PVS-Studio は新しいコードまたは変更されたコードに対してのみ警告を発行します。 .cpp ファイルの先頭に空の行が追加された場合、アナライザーは実際には何も変更されていない状況をサイズアップし、静かなままになります。抑制された警告に関する情報を含むファイルをバージョン管理システムに入れることができます。ファイルが大きくても、頻繁にアップロードする必要がないので問題ありません。

開発者には、新しく作成および変更されたコードに関連する警告のみが表示されます。したがって、彼らが言うように、翌日からアナライザーの使用を開始できます。後で技術的負債に戻って、徐々にエラーを修正し、アナライザーを微調整することができます。

これはすべて、分析自体やエラー検索に直接関係していないようです。それでも、これらの機能は、複雑なプロジェクトで静的分析を実装し、定期的に使用する上で極めて重要な役割を果たします。同時に、質の高いサポートをここで口に出してはいけません。ところで、PVS-Studio 開発者の 1 人が、サポートについて非常に良い話をしました。「C++ プログラマーのサポートを引き受けないでください」:) 26MB 文字列リテラル - ホーリー モリー!

診断機能に戻りましょう。

PVS-Studio はタイプミスを見つけるのが得意です。退屈なコードをチェックするのが面倒ではないコードをレビューするときに、アナライザーを追加のヘルパーとして使用します。コード内のバグを見つけるのに役立ちます。一見すると、勉強するのは面白くないように思えます。なぜなら、「どうしてここで間違いを犯すことができるのか...」たとえば、比較関数を見てみましょう:

bool FaceTypedBSpline::isEqual(const TopoDS_Face &faceOne,
 const TopoDS_Face &faceTwo) const
{
 ....
 if (surfaceOne->IsURational() != 
 surfaceTwo->IsURational())
 return false;
 if (surfaceTwo->IsVRational() != 
 surfaceTwo->IsVRational())
 return false;
 if (surfaceOne->IsUPeriodic() != 
 surfaceTwo->IsUPeriodic())
 return false;
 if (surfaceOne->IsVPeriodic() != 
 surfaceTwo->IsVPeriodic())
 return false;
 if (surfaceOne->IsUClosed() != 
 surfaceTwo->IsUClosed())
 return false;
 if (surfaceOne->IsVClosed() != 
 surfaceTwo->IsVClosed())
 return false;
 if (surfaceOne->UDegree() != 
 surfaceTwo->UDegree())
 return false;
 if (surfaceOne->VDegree() != 
 surfaceTwo->VDegree())
 return false;
 ....
}

そのようなコードをレビューするのはなんてつまらないことでしょう。次の問題を指摘するプログラムが役に立ちます:

if (surfaceTwo->IsVRational() != 
 surfaceTwo->IsVRational())

問題が考案されたようですか? PVS-Studio チームは、面白い (またはがっかりする) 記事「The Evil within the Comparison Functions」を書きました。 Chromium、MongoDB、Qt、FreeBSD、Unreal Engine 4、GDB、GCC などのプロジェクトで見つかった類似のバグが多数挙げられています。残念ながら、実際には泣きそうです。

では、最後の例に移りましょう。 PVS-Studio の作成者は、C++ 言語開発の主な傾向を監視し、最近存在しない新しいエラー パターンを診断します。たとえば、アナライザーは for のイテレーターの無効化を検出します。 範囲ベースのループ。 ClickHouse プロジェクトの実例:

using Strings = std::vector<std::string>;
....
Strings input_files;
....
for (const String filename : input_files)
{
 ....
 if (FS::is_directory(file))
 {
 input_files.erase(
 std::remove(input_files.begin(),
 input_files.end(),
 filename) ,
 input_files.end() );

 getFilesFromDir(file, input_files, recursive);
 }
 ....
}

アナライザーはここで V789 警告を発行し、input_files のループ内での変更を示します。

ですから、この件に関して私が言わなければならないのはそれだけです。プロジェクトの規模と複雑さが増しています。静的分析ツールは、高レベルのコード品質を維持し、バグやゼロデイ脆弱性を見つけるコストを削減するのに役立ちます。したがって、PVS-Studio やその他のコード アナライザーを試してみてください。これらのツールは、一度だけではなく、定期的に使用することを意図していることを忘れないでください。

ご清聴ありがとうございました。敬具、PVS-Studio チーム。

追加リンク

  1. PVS-Studio をダウンロードします (#modernescpp を忘れないでください)
  2. エラー ベース。コード作成のトピックに関する講演や記事の準備をする際に、上記の情報を使用してください;)
  3. PVS-Studio の内部