メモリ解放漏れ・メモリ二重解放は組込みエンジニアにとって、背筋が凍る単語だ。

それは、即、残業しなさいという意味に転じる。

そこから、泥沼のデバッグにハマることがよくある。

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

オープンソース 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