• このエントリーをはてなブックマークに追加

メモリ解放漏れ・メモリ二重解放は組込みエンジニアにとって、背筋が凍る単語だ。
それは、即、残業しなさいという意味に転じる。
そこから、泥沼のデバッグにハマることがよくある。

そんな課題をスマートに解決するために、メモリ解放漏れやメモリ二重解放を検出するツール調べてみたので、メモメモ。

オープンソース CppCheckのインストールをしよう

Cppcheckを使うことでメモリ解放漏れを静的解析で見つけることが可能だ。CppCheckはその他にも、アロケーション(確保と解放)の不一致(メモリ二重解放),バッファオーバーランの検出ができる。OSSなので、誰でも無料で利用可能。

CppCheckのダウンロードはココから

Cppcheckの使い方の日本語訳は、以下のサイトで公開されている。

(ものすごく感謝!)今回はこれを参考に自分でも試してみる。

cppcheck 日本語マニュアル – 一人ぼっちの共鳴
cppcheck 英語マニュアルはこちちから

Cppcheckでメモリリークを検出する

Cppcheckを利用するには、–enable=allオプションをつけて以下のコマンド実行。

cppcheck --enable=all [フアイル名]

試しにこんなコードを書いてみた。

memory_leak.c

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
int *p = NULL;

printf("*p = %x\n",p);
p = malloc(10);
printf("*p = %x\n",p);

return 0;
}

なかなか、喧嘩を売っているコードだけれども、
これをCppCheckでチェックすると、案の定怒られる。(よしよし (^-^))

$ cppcheck --enable=all memory_leak.c
Checking memory_leak.c...
[memory_leak.c:12]: (error) Memory leak: p
Checking usage of global functions..

自分で定義したメモリ獲得/解放関数のメモリリークをチェックする

次に、ユーザ定義したメモリ獲得/解放関数をチェックする。
普通、C標準のメモリ獲得/解放関数を直接使用することはなく、自前の関数でカスタマイズして使用することが多い。メモリアロケート関数を別ファイルで宣言してみる。

hoge_memory.c

#include "hoge_memory.h"

void *hoge_malloc(void)
{
return malloc(10);
}

memory_leak.c
void hoge_free(void *p)
{
free(p);
}

#include <stdio.h>
#include "hoge_memory.h"

int main(void)
{
char *p = NULL;

printf("*p = %x\n",p);
p = (char *)hoge_malloc();
printf("*p = %x\n",p);

return 0;
}
$ cppcheck --enable=all memory_leak.c hoge_memory.c
Checking hoge_memory.c...
1/2 files checked 40% done
Checking memory_leak.c...
2/2 files checked 100% done
Checking usage of global functions..

Oh! 検出してくれないYo!!(゜д゜)/
こんなときは、–appendオプションを使用する。
使い方は、

cppcheck 窶錀-append=<メモリ獲得・解放関数定義file> <静的解析対象file>
$ cppcheck --enable=all --append=hoge_memory.c memory_leak.c
Checking memory_leak.c...
[memory_leak.c:13]: (error) Memory leak: p
Checking usage of global functions..

これで、、メモリリークを検出しました。

メモリ二重解放を検出する

おまけ。メモリ二重解放もこのとおり発見できます!スゲー。

int main(void)
{
char *p = NULL;

printf("*p = %x\n",p);
p = (char *)hoge_malloc();
printf("*p = %x\n",p);

hoge_free(p);

hoge_free(p);

return 0;
}
$ cppcheck --append=hoge_memory.c memory_leak.c
Checking memory_leak.c...
[memory_leak.c:15]: (error) Deallocating a deallocated pointer: p

使われていない関数宣言

$ cppcheck --append=hoge_memory.c --enable=all memory_leak.c
Checking memory_leak.c...
Checking usage of global functions..
[memory_leak.c:18]: (style) The function 'hogehoge_special' is never used