Valgrind

Valgrind（ヴァルグリンド、）は、メモリデバッグや、メモリリークの検出、スレッドエラーの検出、プロファイリングなどを行うための仮想マシンを利用した自由かつオープンソースソフトウェアのソフトウェア開発ツールである。Valgrindという名前は、北欧神話におけるヴァルハラへの入り口の名に由来しているValgrind FAQ。

Valgrindは元々x86上のLinux用のメモリデバッグツールとして設計されたが、開発が進んだ結果、バグ検出やプロファイラといった動的解析ツールのための汎用のフレームワークへと変化された。Valgrindは多数のLinux関連のプロジェクトで使用されているvalgrind.org's list of users。

 概要 
Valgrindは、本質的にはJITコンパイラ（バイナリ変換）の技術を用いた仮想マシンである。クライアントプログラム（元々のプログラムの意、以下同様）そのものがホストのプロセッサで直接実行されるわけではない。代わりにVEXと呼ぶライブラリを使い、Valgrindはまずクライアントプログラムを中間表現（IR、Intermediate Representation）に変換する。中間表現自体はプロセッサ非依存であり、SSAベースである。変換の後、Valgrindが中間表現をマシンコードに再度変換してホストプロセッサで実行させるが、その前後で「ツール」（下記参照）はIRに対して自由に操作を行うことができる。かなりのパフォーマンスがこれらの変換の過程（およびツールが挿入するコード）で損なわれ、クライアントプログラムはValgrind上では（まったくツールを使用しない場合でも）通常より4〜5倍低速に動作する。しかし、仮想マシンによるIRの形態は計測・解析・デバッグには適している。これによりツールの開発が簡単になり、大半のクライアントプログラムでは、デバッグ中のこの程度の性能の低下は大きな問題とはならない。

システムコールも、ホストOSのシステムコールを呼び出す前にValgrindで一度ハンドリングされる。仮想マシンとして仮想化するのはCPUとメモリのみであり、それ以外のハードウェアはホストOSのものをそのまま使う。

上記はクライアントプログラムの挙動をValgrindにて透過的に書き換える機能だが、それ以外にクライアントプログラムから明示的にValgrindの機能を呼び出すこともできる。この機能はクライアントリクエストと呼ばれており、Valgrindの有無確認や設定変更、クライアントプログラム側で管理しているメモリやスタックをValgrindへ追加、発生したエラーの出力などを提供する。Valgrindが透過的に書き換えた処理についても、Valgrind内部ではクライアントリクエストとしてValgrindへ渡される場合がある。

 ライセンス 
ValgrindはGNU General Public Licenseの元でリリースされている自由ソフトウェアである。ただし、クライアントリクエストを明示的に発行したい場合に必要となるValgrindのヘッダファイルに限り、四条項BSDライセンスを採用している。

 ツール 
Valgrindには、多数のツールが含まれている。また、外部から提供されているものもある。これらのツールは共有ライブラリとして提供される。Valgrindはクライアントプログラムをロードする際、動的リンカのプリロード機能を利用し、指定されたツールをクライアントプログラムが指定した共有ライブラリよりも先にロードする。これによりクライアントプログラムが本来参照している共有ライブラリのシンボルをValgrindのツールへ先にリゾルブし、挙動を書き換える。

 Memcheck 
最もよく利用されている標準のツールは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の重大な制約事項は、ヒープメモリに対するチェックツールであり、スタック変数・静的変数に対する境界違反を検出することができない点であるValgrind FAQ。下記のコードは、コメントに示すようなエラーが存在するにもかかわらず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;
}

この種類のエラーが検出できないと、ソフトウェアがバッファオーバーランを生じた場合、古典的なスタック破壊の脆弱性攻撃に対してセキュリティホールになりうるため、注意が必要である。

OSの標準Cライブラリ等の実装に起因する既知の問題で、実用上障害にならないものについては、エラーの出力を抑止することができる。

 その他 
Memcheck以外に、Valgrindには下記のツールが標準で同梱されている。

 Cachegrind：キャッシュプロファイラ。グラフィカルユーザインタフェースのKCacheGrindを含む。
 Callgrind：コールグラフ生成。キャッシュとブランチ予測用のプロファイラ。
 Helgrind：スレッドエラーの検出。マルチスレッドのコードにおける競合状態を検出可能なツール
 DRD：スレッドエラーの検出
 Massif：ヒーププロファイラ
 DHAT：動的ヒープ解析
 SGCheck：（実験的な）スタック配列とグローバル配列のオーバーラン検出
 BBV：（実験的な）基本ブロックベクター生成ツール
 Lackey：ツールのサンプルコード
 Nulgrind：何もしないツール（ベンチマーク用およびサンプル用）

このツールはバージョン3.2.0の時点で削除された。

 Addrcheck：Memcheckの軽量版であり、少ないメモリ消費で高速に動作するが、少ないメモリの問題しか検出できない。

 サポートされているプラットフォーム 
バージョン3.23.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は限定的なサポートのみ）
 FreeBSD - x86、x86-64（以上、11.3-RELEASE以降）、ARM（14.0-RELEASE以降、64ビット）
 Solaris、illumos - x86、x86-64（以上、Solaris 11以降）

そのほか、Unix系プラットフォームや新しいCPUアーキテクチャへの非公式な移植版が存在する。公式に認知されているのは以下の通り。

 NetBSD - x86、x86-64、ARM
 Linux - RISC-V（64ビット）

Microsoft Windows向けには2011-2013年に開発されていたが、その後停滞している。Windowsでは共有ライブラリのプリロードがとしてセキュリティ侵害であると定義されており、WinSxSなどの技術を用いて実行ファイルと共有ライブラリの関係を固定化する指針を採用しているため、これを突破することが難しいことに依る。代替手段として、Linux上で動作するWindowsソフトウェアをデバッグするためWineと接続することができる実験的なバージョンが存在する。プラットフォームのサポートを増やすことは長期的な目標であるが、プロジェクトの性質から非常に多くの作業を必要とする。

 開発者 
Valgrindの元々の開発者は、Julian Sewardであり、彼は2006年にValgrindに関する功績でGoogle-O'Reilly Open Source Awardを受賞したvalgrind.org's list of awardsGoogle-O'Reilly Open Source Awards - Hall of Fame。他にも多数の開発者も重要な貢献を行っており、Cerion Armour-Brown、Jeremy Fitzhardinge、Tom Hughes、Nicholas Nethercote、Paul Mackerras、Dirk Mueller、Josef Weidendorfer、Robert Walshなどが挙げられる。

 脚注 

 参考文献 



 外部リンク 


 Valgrind ドキュメント
 Valgrind Howto（2002年の古いドキュメント）
 Projects using Valgrind

Category:デバッガ
Category:ソフトウェア開発ツール
Category:オープンソースソフトウェア
Category:エミュレーションソフトウェア
Category:仮想化
Category:メモリ管理ソフトウェア