Valgrind

Valgrind（ヴァルグリンド、[ˈvælɡrɪnd]）は、メモリデバッグや、メモリリークの検出、スレッドエラーの検出、プロファイリングなどを行うための仮想機械を利用したソフトウェア開発ツールである。Valgrindという名前は、北欧神話におけるヴァルハラへの入り口の名に由来している。 Valgrindは元々x86上のLinux用のメモリデバッグツールとして設計されたが、開発が進んだ結果、バグ検出やプロファイラといった動的解析ツールのための汎用のフレームワークとなっている。Valgrindは多数のLinux関連のプロジェクトで使用されている。ValgrindはGNU General Public Licenseの元でリリースされているフリーソフトウェアである。 Valgrindは、本質的にはJITコンパイラ（バイナリ変換）の技術を用いた仮想機械である。元々のプログラムそのものがホストのプロセッサで直接実行されるわけではない。代わりにVEXと呼ぶライブラリを使い、Valgrindはまずプログラムを中間表現（IR、Intermediate Representation）に変換する。中間表現自体はプロセッサ非依存であり、SSAベースである。変換の後、Valgrindが中間表現をマシンコードに再度変換してホストプロセッサで実行させるが、その前後で「ツール」（下記参照）はIRに対して自由に操作を行うことができる。かなりのパフォーマンスがこれらの変換の過程（およびツールが挿入するコード）で損なわれ、プログラムはValgrind上では（まったくツールを使用しない場合でも）通常より4〜5倍低速に動作する。しかし、仮想機械によるIRの形態は計測・解析・デバッグには適している。これによりツールの開発が簡単になり、大半のプロジェクトでは、デバッグ中のこの程度の性能の低下は大きな問題とはならない。 システムコールも、ホストOSのシステムコールを呼び出す前にValgrindで一度ハンドリングされる。仮想機械として仮想化するのはCPUとメモリのみであり、それ以外のハードウェアはホストOSのものをそのまま使う。 Valgrindには、多数のツールが含まれている。また、外部から提供されているものもある。 最もよく利用されている標準のツールはMemcheckである。Memcheckはほぼすべての命令に特別な計測用のコードを挿入し、「正当性」（初期化が行われるまでは、割り当て済みでないメモリはすべて無効であるか、未定義である）があり、「アドレス可能」（メモリアドレスが割り当て済みで、解放されていないメモリブロックを指している）であるかという情報が、それぞれVビットおよびAビットに格納されているかを追跡する。データは移動したり加工されたりするが、計測用のコードは1ビットレベルで正確であるようにA、Vビットを追跡する。他のメモリチェックツール（IBM Rational Purify）などは、対照的に未初期化メモリのコピーの検出のみ行う（ただし、必ずしも問題があるわけではない）。 さらに、Memcheckは標準のCメモリアロケータを独自の実装に置き換え、割り当て済みブロックの前後にメモリガード（無効に設定されたAビットを持っている）を挿入する。この機能により、Memcheckはプログラムが割り当てられたブロックよりわずかに外側の領域を読み書きするoff-by-oneエラーを検出できる（この問題に対する別の対応策として、コンパイラに境界を持ったポインタを実装し、特にヒープではなくスタックに確保されたメモリのメモリエラーの検出漏れを低減させる方法があるが、計測するバイナリコードをすべてリコンパイルする必要がある）。 Memcheckが検出や警告可能な問題には、下記のものがある。 初期化されていないメモリの使用 freeされたメモリの読み書き mallocされたブロックの終端以降への読み書き メモリリーク こうした機能への代償として性能が低下する。Memcheckの元で動作するプログラムはValgrindなしで動作する場合と比べて5倍から20倍遅く、より多くのメモリを使用する（メモリ確保ごとにかなりのメモリを追加で消費する）。したがって、ほとんどの開発者は常にMemcheck（あるいは他のValgrindツール）の元でコードを走らせることはしない。特定のバグを解析したり、（Memcheckが検出可能な種類の）潜在的なバグがないことを検証するために使用するのが最も典型的な方法である。 パフォーマンスのペナルティに加えて、Memcheckの重大な制約事項は、ヒープメモリに対するチェックツールであり、スタック変数・静的変数に対する境界違反を検出することができない点である。下記のコードは、コメントに示すようなエラーが存在するにもかかわらずMemcheckでは合格となる。これらの問題を検出するためにSGCheckが開発中である。 int Static[5]; int main(void) { int Stack[5]; Static[5] = 0; /* Static[0] から Static[4] が存在し、Static[5] は境界外 */ Stack [5] = 0; /* Stack[0] から Stack[4] が存在し、Stack[5] は境界外 */ return 0; } この種類のエラーが検出できないと、ソフトウェアがバッファオーバーランを生じた場合、古典的なスタック破壊の脆弱性攻撃に対してセキュリティホールになりうるため、注意が必要である。 Memcheck以外に、Valgrindには下記のツールが標準で同梱されている。 Cachegrind：キャッシュプロファイラ。グラフィカルユーザインタフェースのKCacheGrindを含む。 Callgrind：コールグラフ生成。キャッシュとブランチ予測用のプロファイラ。 Helgrind：スレッドエラーの検出。マルチスレッドのコードにおける競合状態を検出可能なツール DRD：スレッドエラーの検出 Massif：ヒーププロファイラ DHAT：動的ヒープ解析 SGCheck：（実験的な）スタック配列とグローバル配列のオーバーラン検出 BBV：（実験的な）基本ブロックベクター生成ツール Lackey：ツールのサンプルコード Nulgrind：何もしないツール（ベンチマーク用およびサンプル用） このツールはバージョン3.2.0の時点で削除された。 Addrcheck：Memcheckの軽量版であり、少ないメモリ消費で高速に動作するが、少ないメモリの問題しか検出できない。 バージョン3.10.0現在、Valgrindは以下のプラットフォームをサポートしている。 Linux - x86、x86-64、ARM（32ビット/64ビット）、PPC32、PPC64、s390x、MIPS32、MIPS64 Android - ARM（2.3以降）、x86（4.0以降）、MIPS32 macOS - x86、x86-64、（OS X 10.9以降。10.8は限定的なサポートのみ） そのほか、Unix系プラットフォームへの非公式な移植版が存在する（FreeBSDやNetBSDなど）。 Microsoft Windows向けの移植版は現時点では存在しない（また、短期的にも公式な計画はない）が、Linux上で動作するWindowsソフトウェアをデバッグするためWineと接続することができる実験的なバージョンが存在する。プラットフォームのサポートを増やすことは長期的な目標であるが、プロジェクトの性質から非常に多くの作業を必要とする。 Valgrindの元々の開発者は、Julian Sewardであり、彼は2006年にValgrindに関する功績でGoogle-O'Reilly Open Source Awardを受賞した。他にも多数の開発者も重要な貢献を行っており、Cerion Armour-Brown、Jeremy Fitzhardinge、Tom Hughes、Nicholas Nethercote、Paul Mackerras、Dirk Mueller、Josef Weidendorfer、Robert Walshなどが挙げられる。