Valgrindを使ってC言語のメモリリークを簡単にチェックしよう

プログラミング言語Cで開発を行う際、プログラムのメモリ管理は非常に重要なポイントです。メモリの解放漏れ（メモリリーク）やアクセス違反は、予期せぬバグやクラッシュを引き起こす原因となります。これらの問題を未然に防ぐのに、valgrindは結構便利です。

## Valgrindとは？

Valgrindは、プログラムのメモリ使用状況を解析するためのツールです。メモリリーク、アクセス違反、不正なメモリアクセスなどを検出し、詳細な情報をレポートとして出力してくれます。Linux系OS（Ubuntu, CentOS, Arch Linuxなど）で利用可能で、C/C++のデバッグには欠かせないツールの一つです。
僕も全然詳しくないですが、leaksコマンドが使えない環境でC言語を使う必要がある時、調べて見つけました。しかも使いこなせたら結構強そう

## インストール方法

まずは、Valgrindをインストールしましょう。

```bash
sudo apt-get install valgrind
```

## Valgrindの基本的な使い方

### コマンドの概要

Valgrindを使ってプログラムの実行を追跡するためには、以下のコマンドを使用します。

```bash
valgrind [オプション] ./実行ファイル [引数]
```

### よく使うオプション

- `--leak-check=full`：メモリリークに関する詳細な情報を表示します。
- `--track-origins=yes`：未初期化メモリの使用箇所を特定します。
- `--show-leak-kinds=all`：全ての種類のメモリリーク（確保したが解放されていないメモリ、無効な解放など）を表示します。

これらのオプションを組み合わせて、メモリリークをチェックしてみましょう。

## メモリリークのチェック方法

以下のようなメモリリークのある簡単なCプログラムを例にして、Valgrindを使ったメモリチェックを実行します。

```c
// memory_leak_example.c
#include <stdio.h>
#include <stdlib.h>

void create_memory_leak() {
    int *leak = (int*) malloc(10 * sizeof(int));
    leak[0] = 42;
    // メモリを解放し忘れている
}

int main() {
    create_memory_leak();
    return 0;
}
```

上記のプログラムでは、`malloc`で確保したメモリが`free`されていないため、メモリリークが発生します。このプログラムをコンパイルし、Valgrindを使ってチェックしてみましょう。

```bash
gcc -g -o memory_leak_example memory_leak_example.c
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all ./memory_leak_example
```

### 出力結果の確認

Valgrindの出力結果を確認すると、以下のようなメッセージが表示されます。

```
==12345== Memcheck, a memory error detector
==12345== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12345== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==12345== Command: ./memory_leak_example
==12345==
==12345== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==12345==    at 0x4C2B975: malloc (vg_replace_malloc.c:299)
==12345==    by 0x109156: create_memory_leak (memory_leak_example.c:6)
==12345==    by 0x109179: main (memory_leak_example.c:11)
==12345==
==12345== LEAK SUMMARY:
==12345==    definitely lost: 40 bytes in 1 blocks
==12345==    indirectly lost: 0 bytes in 0 blocks
==12345==      possibly lost: 0 bytes in 0 blocks
==12345==    still reachable: 0 bytes in 0 blocks
==12345==         suppressed: 0 bytes in 0 blocks
==12345==
==12345== For counts of detected and suppressed errors, rerun with: -v
==12345== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
```

### 出力の解釈

- `definitely lost` は、確保したが解放されなかったメモリを指します。上記の例では、`malloc`で確保されたメモリ（40バイト分）が解放されずに失われていることが示されています。
- `at 0x4C2B975: malloc` の部分は、メモリを確保した関数`malloc`の呼び出し元を特定しています。
- `by 0x109156: create_memory_leak` は、`create_memory_leak`関数内のどの行でメモリを確保したか（`memory_leak_example.c:6`）を示しています。

## メモリリークの修正

上記のプログラムを修正して、メモリリークを解消してみましょう。`create_memory_leak`関数に`free`を追加します。

```c
// memory_leak_example.c
#include <stdio.h>
#include <stdlib.h>

void create_memory_leak() {
    int *leak = (int*) malloc(10 * sizeof(int));
    leak[0] = 42;
    free(leak);  // メモリを解放
}

int main() {
    create_memory_leak();
    return 0;
}
```

再度、コンパイルしてValgrindを実行します。

```bash
gcc -g -o memory_leak_example memory_leak_example.c
valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all ./memory_leak_example
```

この修正版プログラムでは、メモリリークが解消され、Valgrindからのエラー出力も表示されません。

```
==12345== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```

## まとめ

C言語のメモリチェックには、valgrindを使うという手もあります。

valgrindを使う時は、`--leak-check=full`や`--track-origins=yes`、`--show-leak-kinds=all`のオプションが便利らしいです。