閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

Cppcheck(C++ソースの静的解析ツール)

SourceForge.net: cppcheck

Hudsonのプラグインを漁っているときに見つけた、C++ソースコードを静的に解析してくれるオープンソースのツール。面白そうなので試してみました。

インストール

githubにソースが公開されているので、git cloneなりgithub上のアーカイブをダウンロードするなりしてソースを落としてビルドします。Windowsの場合VS2008のソリューションファイルが付いているので、VCBuildなりdevenv.exeなりで簡単にビルドすることができます。

使ってみる

VCでビルドするとcli/フォルダの下にdebugもしくはreleaseフォルダができて、その下にcppcheck.exeが作成されます。実行ファイルができたらとりあえず引数無しで実行すると使い方が出てきます。

  • -a オプションで警告を全部表示(省略するとファイル毎に最初の一つだけ表示される)
  • -q オプションで警告以外のメッセージを省略(省略するといろいろな情報も一緒に表示される)

ほか、ディレクトリを指定すればその中のソースファイルすべて、ファイル名を指定すればそのファイルだけを解析します。あとは usage を見てください。

試しに、以下のようなソースに対して実行してみます。

#include <iostream>

class base {
public:
    base() : ptr(new int()) {}

    virtual void hello() = 0;

    int* ptr;
};

class derived : public base {
public:
    ~derived() {
        std::cout << "destructor" << std::endl;
    }

    virtual void hello() {
        std::cout << "Hello" << std::endl;
    }
};

int main()
{
    base* p = new derived();
    p->hello();
    if (1)
        return;

    delete p;
}
c:\hoge>cppcheck.exe -q -a hello.cpp
[hello.cpp:3]: (error) Class base which is inherited by class derived does not have a virtual destructor
[hello.cpp:9]: (possible error) Memory leak: base::ptr
[hello.cpp:28]: (possible error) Memory leak: p

基底クラスのデストラクタが仮想関数になっていなかったり、ものすごく簡単なメモリリークを検出してくれます。他にも二重deleteとかに対応している模様。フリーのツールにしては、結構便利かもしれません。

問題点

少しだけ使ってみたところでは、日本語対応がいまひとつなようで、たまにファイルの解析中に落ちます。とりあえず、 cli/main.cpp にある main 関数の先頭に setlocale(LC_ALL, ""); を挿入したら回避できそうでした。WinUnitなんかと同じですね……。

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, ""); // これ
    CppCheckExecutor exec;
    return exec.check(argc, argv);
}

また、先ほどのソースの class を struct に変更すると最初のふたつのエラーが検出されなくなります。

struct base {
public:
    base() : ptr(new int()) {}

    virtual void hello() = 0;

    int* ptr;
};

struct derived : public base {
public:
    ~derived() {
        std::cout << "destructor" << std::endl;
    }

    virtual void hello() {
        std::cout << "Hello" << std::endl;
    }
};

単に class キーワードしか拾っていないのでしょう。必要であれば適当にソース書き換えて対応しましょう。