Valgrind

Valgrind（ヴァルグリンド、[ˈvælɡrɪnd]）は、メモリデバッグや、メモリリークの検出、スレッドエラーの検出、プロファイリングなどを行うための仮想機械を利用したソフトウェア開発ツールである。Valgrindという名前は、北欧神話におけるヴァルハラへの入り口の名に由来している。 Valgrindは元々x86上のLinux用のメモリデバッグツールとして設計されたが、開発が進んだ結果、バグ検出やプロファイラといった動的解析ツールのための汎用のフレームワークとなっている。Valgrindは多数のLinux関連のプロジェクトで使用されている。 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はほぼすべての命令に特別な計測用のコードを挿入し、「正当性」（初期化が行われるまでは、割り当て済みでないメモリはすべて無効であるか、未定義である）があり、「アドレス可能」（メモリアドレスが割り当て済みで、解放されていないメモリブロックを指している）であるかという情報が、それぞれ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; } この種類のエラーが検出できないと、ソフトウェアがバッファオーバーランを生じた場合、古典的なスタック破壊の脆弱性攻撃に対してセキュリティホールになりうるため、注意が必要である。 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では共有ライブラリのプリロードがDLLハイジャック（英語版）としてセキュリティ侵害であると定義されており、WinSxSなどの技術を用いて実行ファイルと共有ライブラリの関係を固定化する指針を採用しているため、これを突破することが難しいことに依る。代替手段として、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などが挙げられる。 ^ “Current Releases”. valgrind.org. 2024年7月8日閲覧。 ^ Valgrind FAQ ^ valgrind.org's list of users ^ Valgrind FAQ ^ “pkgsrc/devel/valgrind/”. NetBSD CVS Repositories. NetBSD. 2024年7月9日閲覧。 ^ “petrpavlu/valgrind-riscv64: Valgrind with support for the RISCV64/Linux platform.”. GitHub. Petr Pavlu. 2024年7月9日閲覧。 ^ valgrind.org's list of awards ^ Google-O'Reilly Open Source Awards - Hall of Fame Julian Seward and Nicholas Nethercote. “Using Valgrind to detect undefined value errors with bit-precision”. Proceedings of the USENIX Annual Technical Conference 2005. USENIX Association. 2008年5月4日閲覧。 ポータル FLOSS 公式ウェブサイト Valgrind ドキュメント Valgrind Howto（2002年の古いドキュメント） Projects using Valgrind