はじめに
C/C++のソースコードを静的解析するツールのひとつにCppcheckがあります。 今回は、Cppcheckを使って実際に静的解析をするやりかたを紹介します。
Cppcheckのセットアップ
公式サイトでは、Windows版のインストーラへのリンクしかありませんが、Windowsでしか使えないということはありません。
DebianやUbuntuなど、たいていのディストリビューション向けにパッケージが用意されているので、簡単にインストールすることができます。
ただ、ちょっとバージョンが古かったりすることもあるので、今回はあえてパッケージによらず最新のmasterをお試しで使ってみることにします。 その場合の情報は開発者向けページにあります。
最初にCppcheckのソースコードをcloneします。
% git clone git://github.com/danmar/cppcheck.git
次に、readme.mdにあるリリースビルドの手順を参考に、インストールします。
% sudo make PREFIX=/usr/local SRCDIR=build CFGDIR=/usr/local/share/cppcheck/cfg HAVE_RULES=yes CXXFLAGS="-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-unused-function" install
readme.mdではインストールせずに使う想定ですが、今回は/usr/localにインストールするものとします。1
Cppcheckを使ってみる
Cppcheckのセットアップができたので、実際に使ってみましょう。
例として、ククログでも何度もとりあげている、全文検索エンジンGroongaでやってみましょう。
すでに、Groongaのリポジトリをgroonga.clean
ディレクトリへとcloneしてあるものとします。
% /usr/local/bin/cppcheck --enable=all groonga.clean 2> cppcheck-master-groonga-master.log
Cppcheckのヘルプにもありますが、--enable=all
をつけるのがオススメ設定です。
--enable=all
では、次の観点からチェックを行います。
-
error メモリリークやNULLポインタの参照の可能性のある箇所を指摘
-
warning 未初期化の変数を使用している箇所などを指摘
-
performance 冗長な代入など、無駄な処理がある箇所を指摘
-
portability 移植性の観点から問題のある箇所を指摘
-
style 未使用の変数などを指摘
-
information Cppcheckの挙動に関する補足情報を出力(オススメのCppcheckのオプションなど)
ほかにも、型や関数の付加情報を追加してチェックを行うことができます。
付加情報というのは、メモリの確保がmalloc
で、それに対応して解放するのがfree
でというようなことです。
こういったリソースの割り当てと解放というのは、プラットフォームであったりライブラリー特有の情報であることが多いので、そのための設定ファイルが標準でいくつか用意されています。
-
avr.cfg
-
cppcheck-cfg.rng
-
gnu.cfg
-
gtk.cfg
-
microsoft_sal.cfg
-
posix.cfg
-
qt.cfg
-
sdl.cfg
-
std.cfg
-
windows.cfg
このうち、std.cfg
は自動で読み込まれます。--force
というオプションもあり、これを使うとすべての.cfgを強制的に読み込ませることができます。
cppcheck
を実行すると、解析結果が大量に出力されます。適宜リダイレクトしておくとよいでしょう。
ログは次のような形式で出力されます。
[対象ファイル:行]: (カテゴリ) 検出した問題点
カテゴリというのは、すでに紹介した、error
、warning
、performance
、portability
、style
、information
のいずれかです。
参考までにどんなふうに出力されるか、実際のログを抜粋します。
[groonga.clean/bindings/php/groonga.c:112]: (style) Variable 'rc' is assigned a value that is never used.
[groonga.clean/bindings/php/groonga.c:124]: (style) Variable 'res_id' is assigned a value that is never used.
[groonga.clean/bindings/php/groonga.c:154]: (style) Variable 'rc' is assigned a value that is never used.
[groonga.clean/bindings/php/groonga.c:109]: (error) Memory leak: ctx
[groonga.clean/bindings/php/php_groonga.h:13]: (error) Invalid number of character '{' when these macros are defined: '__cplusplus'.
[groonga.clean/bindings/python/ql/groongaql.c:35]: (style) Unused variable: rc
[groonga.clean/bindings/python/ql/groongaql.c:66]: (style) Variable 'grn_ctx_fin' is assigned a value that is never used.
[groonga.clean/bindings/python/ql/groongaql.c:79]: (style) Unused variable: rc
[groonga.clean/bindings/python/ql/groongaql.c:98]: (style) Unused variable: rc
[groonga.clean/bindings/python/ql/groongaql.c:119]: (style) Unused variable: rc
[groonga.clean/bindings/python/ql/groongaql.c:134]: (style) Unused variable: rc
[groonga.clean/lib/com.c]: (information) Too many #ifdef configurations - cppcheck only checks 12 of 61 configurations. Use --force to check all configurations.
[groonga.clean/lib/com.c:1085] -> [groonga.clean/lib/com.c:1106]: (warning) Either the condition 'if(ev)' is redundant or there is possible null pointer dereference: ev.
[groonga.clean/lib/com.c:1086] -> [groonga.clean/lib/com.c:1106]: (warning) Either the condition 'if(ev)' is redundant or there is possible null pointer dereference: ev.
上記のようなログを採取できたら、検出された箇所をチェックしていきましょう。
大量に検出されるので、error
やwarning
にしぼりこんで重点的に確認するとよいでしょう。ただし、Cppcheckも誤検出するケースがあるので万能ではありません。
まとめ
C/C++のソースコードを静的解析するツールであるCppcheckを紹介しました。 ツールをうまく使って、これまで見落していた潜在的な問題点がないか、これを機会に調べてみるのはいかがでしょうか。
-
インストールしていない場合には、常にカレントディレクトリにcfgディレクトリがあることを想定した振舞いをします。そのためclone先のディレクトリで常に実行しないとエラーになります。 ↩