Valgrind

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

Valgrindとはメモリを主眼に置いた、メモリでバッグやメモリリークの検出、プロファイリング等を行うツールです。
C言語は特にメモリ周辺のバグが多く現在でも多くのソフトウェアで日々バグが発見、修正されています。
こういった問題はprintデバッグでは発見しづらく、これを手助けしてくれるツールですので積極的に利用するのがよいでしょう。


Valgrind

インストール

まずはインストールから。
gcc等の環境はインストールされているはずなので省略します。

// Debian系
$ apt-get install valgrind

// Red Hat系
$ yum install valgrind
//or
$ dnf install valgrind
		


機能

Valgrind(tools)等によると様々な機能があるようです。

シグナルはint型の整数で定義されています。有名なシグナルをいくつか紹介しましょう。

Memcheckメモリエラー検出ツール。特にC、C++に向いています
Cachegrindキャッシュプロファイラ。GUIはKCacheGrind。
Callgrindコールグラフ、つまり関数呼び出しの可視化を行う
Helgrindスレッドエラーの検出。マルチスレッドの競合状態を検出してくれる
DRDスレッドエラーの検出。Helgrindとはアプローチが異なり、検出する問題も違うらしい
Massifヒーププロファイラ。メモリ使用量を抑えたりするのに使えるでしょう
DHAT動的ヒープ解析
SGCheck実験段階とのこと。Memcheckと似ているがこちらはスタックやグローバル領域向け
BBV実験段階とのこと。基本ブロックベクター生成ツールらしい...
Lackeyツールのサンプルコード
Nulgrind何もしません。ベンチマークやサンプル用


使い方

まずは定番なHello Worldから。

#include <stdio.h>

int main(void)
{
        printf("Hello World\n");

        return 0;
} 

コンパイル時には'-g'オプションを忘れずに。
$ gcc -g -o hello hello.c
$ ./hello
Hello World 

Valgrindの使用方法は、valgrindコマンドに実行コマンドを渡します
$ valgrind ./hello
==30444== Memcheck, a memory error detector
==30444== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==30444== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==30444== Command: ./hello
==30444== 
Hello World
==30444== 
==30444== HEAP SUMMARY:
==30444==     in use at exit: 0 bytes in 0 blocks
==30444==   total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==30444== 
==30444== All heap blocks were freed -- no leaks are possible
==30444== 
==30444== For counts of detected and suppressed errors, rerun with: -v
==30444== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 


実行時には使用したい機能毎にオプションを指定できます。
通常valgrindを使う場合はメモリリークチェックが主になります。
メモリリークを検出するには'--leak-check'オプションを利用します。
このコードはよくあるアクセスしてはいけない領域への書き込みです
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
        int *p;

        p = malloc(4);
        p[4] = 0; //NG

        return 0;
} 

見事に検出されています。'-g'オプションをつけているので、行数まで表示されています。
$ valgrind --leak-check=full ./hoge
==32456== Memcheck, a memory error detector
==32456== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==32456== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==32456== Command: ./hoge
==32456== 
==32456== Invalid write of size 4
==32456==    at 0x400544: main (hoge.c:9)
==32456==  Address 0x5203050 is 12 bytes after a block of size 4 alloc'd
==32456==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32456==    by 0x400537: main (hoge.c:8)
==32456== 
==32456== 
==32456== HEAP SUMMARY:
==32456==     in use at exit: 4 bytes in 1 blocks
==32456==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==32456== 
==32456== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==32456==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32456==    by 0x400537: main (hoge.c:8)
==32456== 
==32456== LEAK SUMMARY:
==32456==    definitely lost: 4 bytes in 1 blocks
==32456==    indirectly lost: 0 bytes in 0 blocks
==32456==      possibly lost: 0 bytes in 0 blocks
==32456==    still reachable: 0 bytes in 0 blocks
==32456==         suppressed: 0 bytes in 0 blocks
==32456== 
==32456== For counts of detected and suppressed errors, rerun with: -v
==32456== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) 

他にはこのような場合も検出できます。

フリーを行っていない
int func(void)
{
        p = malloc(4);

        // pをfreeしていない
        return 0;
	} 

ダブルフリー(同じポインタを2回feeする)
        p = malloc(4);
        free(p);
        free(p); //pはfree済み 

freeした領域へのアクセス
        p = malloc(4);
        free(p);
        p[0] = 0; //free済み領域への書き込み 

初期化していない領域の参照
        int x;
        printf("%d\n", x); //xは未初期化 


メモリリークチェック以外にも、他の機能もありますの簡単に使い方を見ましょう。
ヒーププロファイラ
$ valgrind --tool=massif ./hoge 

コールトレース
$ valgrind --tool=callgrind ./hoge 


まとめ

C言語は他の言語に比べて低級なために細かな所までアクセスするが為にバグも多く、特にメモリ周りはその主な原因となっています。
機械的な物なのですから、人間が根性で頑張るのではなくデバッグもプログラムで行うのが自然でしょう。
Valgrindはこういった要求に応えるためのツールです。楽をして開発を行うためにも選択肢の1つに入れておきましょう


リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
Dustin Boswell,Trevor Foucher,須藤 功平,角 征典

オライリージャパン
売り上げランキング : 1022

Amazonで詳しく見る by AZlink

テスト駆動開発による組み込みプログラミング ―C言語とオブジェクト指向で学ぶアジャイルな設計テスト駆動開発による組み込みプログラミング ―C言語とオブジェクト指向で学ぶアジャイルな設計
James W. Grenning,蛸島 昭之,笹井 崇司

オライリージャパン
売り上げランキング : 34157

Amazonで詳しく見る by AZlink