7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Valgrindは強力なメモリデバッグツール。メモリリーク、未初期化メモリの使用、バッファオーバーフローを検出できる。

「動いてるけどなんかおかしい」ってときに使うと原因が分かることが多い。

インストール

# Ubuntu/Debian
sudo apt install valgrind

# macOS (x86のみ、ARM非対応)
brew install valgrind

# WSL (Windows Subsystem for Linux)
sudo apt install valgrind

基本的な使い方

# デバッグ情報付きでコンパイル
g++ -g -O0 program.cpp -o program

# Valgrindで実行
valgrind ./program

# 詳細なリーク情報
valgrind --leak-check=full ./program

# より詳細な情報
valgrind --leak-check=full --show-leak-kinds=all ./program

メモリリークの例と検出

単純なリーク

// leak.cpp
#include <iostream>

void memory_leak() {
    int* p = new int[100];
    // delete[] p を忘れた!
}

int main() {
    memory_leak();
    return 0;
}

出力:

==12345== HEAP SUMMARY:
==12345==     in use at exit: 400 bytes in 1 blocks
==12345==   total heap usage: 1 allocs, 0 frees, 400 bytes allocated
==12345== 
==12345== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1
==12345==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/...)
==12345==    by 0x400684: memory_leak() (leak.cpp:5)
==12345==    by 0x400695: main (leak.cpp:10)

修正版

void memory_leak_fixed() {
    int* p = new int[100];
    // 使用...
    delete[] p;  // 修正!
}

// さらに良い方法: スマートポインタ
#include <memory>

void no_leak() {
    auto p = std::make_unique<int[]>(100);
    // 自動解放
}

未初期化メモリの使用

// uninit.cpp
#include <iostream>

int main() {
    int x;  // 未初期化
    if (x > 0) {  // UB!
        std::cout << "positive" << std::endl;
    }
    return 0;
}

検出:

==12345== Conditional jump or move depends on uninitialised value(s)
==12345==    at 0x400684: main (uninit.cpp:6)

範囲外アクセス

// overflow.cpp
#include <iostream>

int main() {
    int arr[5];
    arr[10] = 42;  // 範囲外書き込み
    return 0;
}

検出:

==12345== Invalid write of size 4
==12345==    at 0x400684: main (overflow.cpp:6)
==12345==  Address 0x... is 20 bytes after a block of size 20 alloc'd

解放済みメモリへのアクセス

// use_after_free.cpp
#include <iostream>

int main() {
    int* p = new int(42);
    delete p;
    std::cout << *p << std::endl;  // 解放済み!
    return 0;
}

検出:

==12345== Invalid read of size 4
==12345==    at 0x400684: main (use_after_free.cpp:7)
==12345==  Address 0x... is 0 bytes inside a block of size 4 free'd
==12345==    at 0x4C2CDFB: operator delete(void*) (...)
==12345==    by 0x400680: main (use_after_free.cpp:6)

二重解放

// double_free.cpp
#include <iostream>

int main() {
    int* p = new int(42);
    delete p;
    delete p;  // 二重解放!
    return 0;
}

検出:

==12345== Invalid free() / delete / delete[] / realloc()
==12345==    at 0x4C2CDFB: operator delete(void*) (...)
==12345==    by 0x400690: main (double_free.cpp:7)
==12345==  Address 0x... is 0 bytes inside a block of size 4 free'd

Valgrindオプション

# メモリリーク詳細
valgrind --leak-check=full --show-leak-kinds=all ./program

# ログをファイルに保存
valgrind --log-file=valgrind.log ./program

# 子プロセスも追跡
valgrind --trace-children=yes ./program

# 特定のリーク種別のみ
valgrind --show-leak-kinds=definite ./program

# 抑制ファイルを使用
valgrind --suppressions=my.supp ./program

# エラー発生時にデバッガ起動
valgrind --vgdb=yes --vgdb-error=1 ./program

リークの種類

種類 説明
definitely lost 確実にリーク(到達不可能)
indirectly lost 他のリークブロックからのみ到達可能
possibly lost リークの可能性あり
still reachable まだ到達可能だが解放されていない

Memcheck以外のツール

# Cachegrind - キャッシュプロファイラ
valgrind --tool=cachegrind ./program

# Callgrind - コールグラフ生成
valgrind --tool=callgrind ./program
kcachegrind callgrind.out.*

# Helgrind - スレッドエラー検出
valgrind --tool=helgrind ./program

# DRD - データレース検出
valgrind --tool=drd ./program

Windows/macOS代替ツール

Windows

  • Visual Studio: メモリ診断ツール
  • Dr. Memory: Valgrind代替
  • AddressSanitizer: MSVC/Clang対応

macOS (ARM)

  • Instruments: Xcode付属
  • AddressSanitizer: Clang対応

AddressSanitizer (ASan)

Valgrindより高速な代替:

# コンパイル
g++ -fsanitize=address -g program.cpp -o program

# 実行(通常通り)
./program

デバッグのベストプラクティス

  1. デバッグビルドで実行: -g -O0
  2. 全てのリークを確認: --leak-check=full
  3. 定期的に実行: CIに組み込む
  4. スマートポインタを使う: リークを防止
  5. RAII: リソース管理の基本

CI/CDへの統合

# .gitlab-ci.yml
test:
  script:
    - g++ -g program.cpp -o program
    - valgrind --error-exitcode=1 --leak-check=full ./program

まとめ

Valgrindは C/C++ のメモリバグを検出する必須ツールです。開発中に定期的に使用することで、メモリリークやバグを早期に発見できます!

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?