cppcheck/ソースをいじってみる

 
1. ソースファイルを取得する
2. 何をチェックしてみたかったか
3. ビルドしてみる
4. ソースを読んでみる
5. ソースをいじってみる

1. ソースファイルを取得する

 ここでソースをいじってみると言っているのは cppcheck 自体のソースのことです。  チェックしたい関数があって、デフォルトではチェックされない。  cfg の設定のみではどうにもならなそうなので、本体のソースをいじってみることにしたのです。  Windows 版であれば「2.1 Windows版ダウンロード・インストール」で示しているサイトから zip 形式でソースをダウンロードできます。

2. 何をチェックしたかったか

 では何をチェックしたかったかというと。  Visual C++SecureZeroMemory という関数がありまして。  いまや、gcc でも非推奨になった bzero と同じ機能で。  gcc では memset を使えということになっています。  似た関数に ZeroMemory というのがあるのですが、何が違うのかというと ZeroMemory はコードによっては、Release でビルドするとオプティマイズアウトされることがあるらしいが、SecureZeroMemory はそれがない・・・と。  つまり確実にその領域をクリアするということらしいです。  実は、ZeroMemorymemset のラッパで SecureZeroMemorymemset_s のラッパであるらしい。  ということは memsetmemset_s に変えるべきなんだな。  というのは置いておいて、以下のようなコードがあるとします。内容は問わないで、チェックだけに目を向けてください。

int main(int argc, char* argv[])
{
    int n;
    int* tmp = &n;

    SecureZeroMemory(tmp, sizeof(tmp));
    memset(tmp, 0, sizeof(tmp));

    return 0;
}
 これを cppcheck にかけると memset の方は

内容: Size of pointer 'tmp' used instead of size of its data.
メッセージ: Size of pointer 'tmp' used instead of size of its data. This is likely to lead to a buffer overflow. You probably intend to write 'sizeof(*tmp)'.
 てな警告が出るんですな。sizeof(tmp) と書いているが、おいおい sizeof(*tmp) の間違いじゃないか?・・・と。  よくあるミスで、つい * をつけそこなっちゃっててクリアするはずの領域が消えてなかったりする。  逆に、型が char だったりしたら消してはいけない領域までクリアしてしまったりする。  SecureZeroMemory も同じ事情なのですが、残念ながら SecureZeroMemory の方は警告が出てくれないのです。  実は、あるプロジェクトで SecureZeroMemory を多用していて、ついやっちゃったときに全部チェックすることになったのですが、人的作業ではたまらんわけです。  で、cppcheck でなんとかならんもんかいな・・・ということです。

3. ビルドしてみる

 とりあえず、Windows 版のソースコードをダウンロードして、展開したら sln という拡張子があるので Visual Studio でビルド (Visual Studio なので make ではないわけです) できるぞ・・・と。  Visual Studio 2010 でビルドしてみたら

プロジェクト ファイルに ToolsVersion="14.0" が含まれています。このツールセットが不明であるか、存在しない可能性があります。その場合は、適切なバージョンの MSBuild をインストールして解決するか、ビルドがポリシー上の理由により特定の ToolsVersion を使用するよう強制されている可能性があります。プロジェクトを ToolsVersion="4.0" として扱います。詳細については、http://go.microsoft.com/fwlink/?LinkId=291333 を参照してください。
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\x64\Microsoft.Cpp.x64.Targets(507,5): error MSB8008: 指定したプラットフォーム ツールセット (v140) はインストールされていないか無効です。サポートされている PlatformToolset 値が選択されていることを確認してください。
 てなエラーになりました。ToolsVersion="14.0"ってのは Visual Studio 2015 のもののようなので、Express をインストールしてビルドしたらうまくいきました。

warning C4389: '==': signed と unsigned の数値を比較しようとしました。
 とか、cppcheck のソースが警告の出るものというのが笑えましたが・・・。

4. ソースを読んでみる

 Size of だとか pointer をキーワードに探してみたら、ありました。
lib/checksizeof.cpp
 の

checkSizeofForPointerSize
 という関数がわたしの目的とする関数のようです。

5. ソースをいじってみる

 ちょっとした試行錯誤があったのですが(きちんとソースを解析してないからいかんのです) 149行目と 150行目の間に

else if (Token::simpleMatch(tok, "SecureZeroMemory (") && tok->strAt(-1) != ".") {
    variable = tok->tokAt(2);
    tokSize = variable->nextArgument();
    tokFunc = tok;
 というコードをいれてビルド。  bin の下にできた
cppcheck-core.dll
cppcheck.exe
 を
C:\Program Files\Cppcheck
 に上書きして、先ほどのソースをチェックしてみたら。  うまくチェックできるようになりました。