C(++)言語: valgrindの使い方 (memcheck)

Kazuki Ohta, 2006/05/20



「Binary Hacks」

(2-1) Memcheck: メモリエラーを検出する

Memcheckが検出出来るエラーには以下のようなモノが有る。

(2-1-1) Memcheck: メモリリーク

static char *s;

void leaking(void)
{
    s = (char*)malloc(100);
    s[0] = 'a';
}

int main(void)
{
    leaking();
    leaking();
    leaking();
}
これをvalgrind ./a.outとして実行する。すると、valgrindの実行結果の最後に以下のように表示される。
==29024== LEAK SUMMARY:
==29024==    definitely lost: 200 bytes in 2 blocks.
==29024==      possibly lost: 0 bytes in 0 blocks.
==29024==    still reachable: 100 bytes in 1 blocks.
==29024==         suppressed: 0 bytes in 0 blocks.
==29024== Use --leak-check=full to see details of leaked memory.
--leak-check=fullオプションを付けて実行してみると、以下のようにリーク箇所を特定出来る。
==29034== 200 bytes in 2 blocks are definitely lost in loss record 2 of 2
==29034==    at 0x1B8FF8A2: malloc (vg_replace_malloc.c:149)
==29034==    by 0x8048387: leaking (in /home/kzk/testprogram/c/valgrind/a.out)
==29034==    by 0x80483BA: main (in /home/kzk/testprogram/c/valgrind/a.out)
==29034== 
==29034== LEAK SUMMARY:
==29034==    definitely lost: 200 bytes in 2 blocks.
==29034==      possibly lost: 0 bytes in 0 blocks.
==29034==    still reachable: 100 bytes in 1 blocks.
==29034==         suppressed: 0 bytes in 0 blocks.

(2-1-2) Memcheck: 初期化されていない値の使用

以下の様なソースコードに対してvalgrindを実行する。
int main(void)
{
  int x;
  printf("%d\n", x);
}
実行結果はこうなる(抜粋)。
==28871== Conditional jump or move depends on uninitialised value(s)
==28871==    at 0x1B9515B9: vfprintf (in /lib/tls/i686/cmov/libc-2.3.5.so)
==28871==    by 0x1B95871F: printf (in /lib/tls/i686/cmov/libc-2.3.5.so)
==28871==    by 0x80483A3: main (in /home/kzk/testprogram/c/valgrind/a.out)
一番左の数字はプロセス番号を示している。

(2-1-3) Memcheck: freeされた領域へのアクセス

int main(void)
{
    char *s = (char*)malloc(10);
    free(s);

    s[0] = 'a';
}
==28890== Invalid write of size 1
==28890==    at 0x80483F5: main (in /home/kzk/testprogram/c/valgrind/a.out)
==28890==  Address 0x1BA49028 is 0 bytes inside a block of size 10 free'd
==28890==    at 0x1B90044F: free (vg_replace_malloc.c:235)
==28890==    by 0x80483EE: main (in /home/kzk/testprogram/c/valgrind/a.out)
また、同じ領域を2回freeしようとすると次のようになる。
int main(void)
{
    char *s = (char*)malloc(10);
    free(s);
    free(s);
}
==28933== Invalid free() / delete / delete[]
==28933==    at 0x1B90044F: free (vg_replace_malloc.c:235)
==28933==    by 0x80483FC: main (in /home/kzk/testprogram/c/valgrind/a.out)
==28933==  Address 0x1BA49028 is 0 bytes inside a block of size 10 free'd
==28933==    at 0x1B90044F: free (vg_replace_malloc.c:235)
==28933==    by 0x80483EE: main (in /home/kzk/testprogram/c/valgrind/a.out)

(2-1-4) Memcheck: mallocされた領域より後の領域へのアクセス

int main(void)
{
    char *s = (char*)malloc(10);
    s[10] = 'a';
}
==28909== Invalid write of size 1
==28909==    at 0x80483AA: main (in /home/kzk/testprogram/c/valgrind/a.out)
==28909==  Address 0x1BA49032 is 0 bytes after a block of size 10 alloc'd
==28909==    at 0x1B8FF8A2: malloc (vg_replace_malloc.c:149)
==28909==    by 0x804839D: main (in /home/kzk/testprogram/c/valgrind/a.out)

(2-1-5) Memcheck: malloc/new/new []とfree/delete/delete []の対応の不一致

C++を用いる。
int main(void)
{
    char *s = new char[10];
    delete s;
}
==29065== Mismatched free() / delete / delete []
==29065==    at 0x1B9006E8: operator delete(void*) (vg_replace_malloc.c:246)
==29065==    by 0x80484BE: main (in /home/kzk/testprogram/c/valgrind/a.out)
==29065==  Address 0x1BB5D028 is 0 bytes inside a block of size 10 alloc'd
==29065==    at 0x1B9000EB: operator new[](unsigned) (vg_replace_malloc.c:197)
==29065==    by 0x80484AD: main (in /home/kzk/testprogram/c/valgrind/a.out)

[ return ]