PVS-Studioを使用したQtプログラムの静的分析の経験

画像 この記事は、かなり大きなプログラム(現時点ではソースコードを含む1665ファイル)の静的解析の最初の経験の結果です。 さらに、これはMicrosoft Visual Studioを使用した初めての経験です。 分析されたプログラムの開発は、Ubuntu、Eclipse CDT、GCCコンパイラでのみ実行されました。

プロジェクトの準備

「スタジオ」に堪能で、Qtプロジェクトの開発方法を長い間学んできた場合は、このセクションをスキップしてください。 VS2010のプロジェクトを準備する私の方法は次のとおりです。

Qtフレームワークに基づいてプログラムを開発しているため、プロジェクトに.proファイルがあります。 このファイルは、プロジェクトを生成するための基礎です。 Qt Webサイト( http://doc.qt.nokia.com/stable/qmake-project-files.html )には、qmakeを使用して「スタジオ」プロジェクトを生成できると記載されています。 これを行うには、次のコマンドを使用します。
$ {QTDIR} \ bin \ qmake.exe -t vcapp -spec $ {QTDIR} \ mkspecs \ win32-msvc2010

次に、プロジェクトファイル* .vcxprojが表示されます。これは、「スタジオ」によって開かれます。 これ以上の操作は必要ありませんでした-プロジェクトは正常にコンパイルされました。

PVS-Studioのインストールと構成

インストールは不可能です。ダウンロード、インストール、再起動すると、メニューに目的のタブ-PVS-Studioがすでにあります。 私はセットアップに少し手を加えなければなりませんでした。 私が知らない理由で、プロジェクトを分析するとき(PVS-Studio->ソリューションのチェック)、PVSはQtヘッダーファイル(QWidget.hやQObject.hなど)を見つけることができませんが、プロジェクトはエラーなしでコンパイルされます。 この状況を修正するには、プロジェクト設定に移動し(プロジェクトを右クリック->プロパティ)、「VC ++ディレクトリ」を選択し、「ディレクトリを含める」セクションでQtヘッダーファイルへのパスを指定します。 さらに、Qt \ includeのルートフォルダーだけでなく、使用するモジュラーサブフォルダーも含める必要があります。 つまり、プロジェクトがコア、gui、xml、sql、network、webkit、openglモジュールを使用していることを.proファイルが示している場合は、include、include \ qtcore、inclide \ qtgui、includeを追加する必要があります\ qtxml、インクルード\ qtxmlpatterns、インクルード\ qtsql、インクルード\ qtnetwork、インクルード\ qtwebkit、インクルード\ qtopengl。 これらのアクションを実装すると、PVS-Studioは正常に動作し始めます。

静的解析

分析には約4時間かかり、その時点でスノーボードをしていました。 それで、それは発見されました:カテゴリー3

このカテゴリでは、 最大 250件 (全体の87 %% )の警告「V001。 'file'のコードフラグメントを分析できません '' 、PVSが特定のファイルの解析に失敗したことを報告しています。 多くの警告は、moc * .cppなどの自動生成ファイルを参照しています。 PVSがこれらのファイルを解析しようとしない場合、私にとってはより便利です。

次に人気のある警告は「V550。 奇妙な正確な比較。 定義された精度との比較を使用することをお勧めします:fabs(A-B)<Epsilonまたはfabs(A-B)> Epsilon 警告の分析により、 8つの偽陽性と1 つの偽陽性が示されました。

このブロックには次の警告があります。 タイプ 'long'のサイズはLLP64 / LP64データモデル間で異なることに注意してください ''
この診断メッセージにより、プログラムで使用されているすべての「長い」タイプを見つけることができます。
もちろん、プログラムに「long」型が存在すること自体はエラーではありません。 ただし、WindowsおよびLinuxで正常に動作する必要がある移植可能な64ビットコードを作成する場合、このタイプが使用されているプログラムテキストのすべてのフラグメントを確認する必要があります。
WindowsとLinuxは、64ビットアーキテクチャ用に異なるデータモデルを使用します。 データモデルとは、int、float、pointerなどの基本データ型のサイズの相関を意味します。 WindowsはLLP64データモデルを使用し、LinuxはLP64データモデルを使用します。 これらのモデルでは、「long」タイプのサイズが異なります。
Windows(LLP64)では、「long」タイプのサイズは4バイトです。
Linux(LP64)では、「long」タイプのサイズは8バイトです。
「long」タイプのサイズの違いにより、ファイル形式が互換性がなくなったり、LinuxおよびWindowsで実行されるコードを開発するときにエラーが発生したりする場合があります。 必要に応じて、PVS-Studioを使用して、 'long'タイプが使用されているすべてのコードフラグメントを確認できます。
私はQtフレームワークを使用しているので、long型を使用することは一般的に口調が悪いことを思い出させてください。クロスプラットフォーム開発にはqint16、qint32およびqint64を使用する必要があります。 唯一の問題は、この場合のPVSの使用がプロジェクト全体の検索よりも優れていることです。 結局のところ、これらの警告は有料製品であるViva64に適用されます。 これらの警告ではコード警告は無効になっています(理解と編集が非常に困難になります)。

プログラムのトライアルのために分析できなかったという警告:
「V111。 可変数の引数で関数 'foo'を呼び出します。 N引数のサイズはmemsizeです”

カテゴリー2

このカテゴリには憂鬱な状況がありました。一般分析(無料分析)に関連する警告-4個(全体の2% )とViva64からの160個の試験警告です。

逆説的に、試験的な警告の大部分は「V112。 危険な魔法の数Nが使用されました。これもカテゴリ3にあります。原則として、PVSがカテゴリ2に属し、カテゴリ3にある部分は謎です。 大まかな検査で約90%の誤検出が示されたため、この警告のアナライザーを改善する必要があると考えています。 真の応答が1つも見つからなかったとさえ言えます。 しかし、私はサンプル全体をチェックしませんでした。なぜなら、試行錯誤がトリックをしたからです-私は疲れています。 この警告によると、マジックナンバーは主に、さまざまなインデントとオフセットの設定などの描画手順で見つかりました。

無料アクセスアラート:

「V537。 'X'アイテムの使用法の正確さを確認することを検討してください ''
アナライザーは、コードの潜在的なミスプリントを検出しました。 このルールは、発見的方法を使用して、次のタイプのエラーを診断しようとします。
int x = static_cast <int>(GetX())* n;
int y = static_cast <int>(GetX())* n;
2行目では、GetY()の代わりにGetX()関数が使用されます。 これは正しいコードです:
int x = static_cast <int>(GetX())* n;
int y = static_cast <int>(GetY())* n;
-誤検知。 コードは次のとおりです。
int width = img_in->width();
int height = img_in->height();

if (width > height) {
if (width > maxWidth) {
height = ( int ) (( float ) maxWidth / width * height);
width = maxWidth;
}
} else {
if (height > maxHeight) {
/**/ width = ( int ) (( float ) maxHeight / height * width);
height = maxHeight;
}
}


* This source code was highlighted with Source Code Highlighter .


「V525。 同様のブロックのコレクションを含むコード。 行N1、N2、N3、…の項目X、Y、Z、...をチェックします -誤検知。

有料アクセス警告:

「V401。 構造体のサイズは、フィールドの順序を変更することで小さくできます。 サイズをNバイトからKバイトに減らすことができます
アナライザーは、メインメモリの無効な使用につながる可能性のあるデータ構造を検出しました。
Viva64が無効をアナウンスする構造の例を考えてみましょう。
struct LiseElement {
bool m_isActive;
char * m_pNext;
int m_value;
};
この構造は、データの調整に関連する64ビットコードで24バイトを占有します。 ただし、フィールドの順序を変更すると、そのサイズは16バイトを占有します。 構造の最適化されたバリアントは次のようになります。
struct LiseElement {
char * m_pNext;
int m_value;
bool m_isActive;
};
...
現時点では、これがどのように可能かを理解することはできませんが、これが真実であれば、これは素晴らしいことです。この警告は私にとって非常に役立ちます、ありがとう。

カテゴリー1

状況はカテゴリー2に似ています: 1つの無料警告と119の支払いのみ。

無料の警告:
「V524。 「Foo_1」関数が「Foo_2」関数と完全に同等であることは奇妙です -誤検知
const qreal&getX()const {
throw std :: runtime_error( "サポートされていない操作エラー");
}

const qreal&getY()const {
throw std :: runtime_error( "サポートされていない操作エラー");
}


有料の警告:

「V103。 memsize型から32ビット型への暗黙的な型変換、
「V104。 算術式のmemsize型への暗黙的な型変換、
「V110。 memsize型から32ビット型への戻り値の暗黙的な型変換、
「V302。 'foo'クラスのメンバー演算子[]には、32ビット型の引数があります。 ここでmemsize-typeを使用します -これらの警告はQtソースコード、特にqtessolator.cppファイルで見つかりました。 真実は、試行錯誤のために検証できませんでした。

一部のエラー、特にV114では、PVS-Studio V121は警告を複製します。 そのため、警告のリストには、同じ行を参照する同じタイプの警告の平均4つのインスタンスがあります。

まとめ

ツールを使用する感覚は2つあります。 私は自分が独創的なプログラマーであるとは考えていないため、このツールはより多くのエラーを明らかにすると想定しました。 実際、修正する価値のあるプロットが1つありました。 自分のことをひどく考えるか、ツールがまだ完全に磨かれていません。

このツールは、 6個2.11% )の無料アラートと278個97.89% )の有料アラートを発行しました(3番目のカテゴリーなし)。 ほとんど無料ではないので、試してさえいられません。 V112 (マジックナンバー)に関連する警告は1つの誤検知を与えますが、多くの警告があります-特に支払いが行われているので、チェックにうんざりします。

このツールを購入しますか? 残念ながら、ありません。 多数の誤検知のため、セットアップと分析に多くの時間を費やしました。 500件近くの警告に対する1つの誤検知は、あまりにも残酷です。 驚くべきことに、有用な警告は3つのカテゴリに分類されました(最も重要ではないことを理解したため)。 自動生成されたファイルで250個のアラートが見つかりました。 そのようなファイルを処理から除外する事前設定(たとえば、Qt mocファイル)を見たいです。 何よりも、警告V401に満足しました(サイズを小さくすることができます)。 これは私が買うものです! すべての警告を購入して、サイズを縮小し、アプリケーションの速度を上げることができます。

ありがとう

Source: https://habr.com/ru/post/J110515/


All Articles