ククログ

株式会社クリアコード > ククログ > C/C++のソースコードをCppcheckで静的解析してみよう

C/C++のソースコードをCppcheckで静的解析してみよう

はじめに

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を実行すると、解析結果が大量に出力されます。適宜リダイレクトしておくとよいでしょう。 ログは次のような形式で出力されます。

[対象ファイル:行]: (カテゴリ) 検出した問題点

カテゴリというのは、すでに紹介した、errorwarningperformanceportabilitystyleinformationのいずれかです。

参考までにどんなふうに出力されるか、実際のログを抜粋します。

[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.

上記のようなログを採取できたら、検出された箇所をチェックしていきましょう。 大量に検出されるので、errorwarningにしぼりこんで重点的に確認するとよいでしょう。ただし、Cppcheckも誤検出するケースがあるので万能ではありません。

まとめ

C/C++のソースコードを静的解析するツールであるCppcheckを紹介しました。 ツールをうまく使って、これまで見落していた潜在的な問題点がないか、これを機会に調べてみるのはいかがでしょうか。

  1. インストールしていない場合には、常にカレントディレクトリにcfgディレクトリがあることを想定した振舞いをします。そのためclone先のディレクトリで常に実行しないとエラーになります。