malloc デバッグ・ツール
malloc サブシステムによって割り当てられたメモリーを正しく管理していないアプリケーションのデバッグは、困難かつ単調になることがあります。 その理由は、エラーの挿入とその結果の症状の露出との間には一般に同時性がないためです。
この困難性に加えて、メモリー割り当てが本来持っている複雑さがあります。その複雑さとは、そこでは大量の割り当てが行われたり、行われなかったり、そして (たぶん) 非同期的にしかも同時にアクセスされ、それらはすべて堅固で効果的な同期を必要とするマルチスレッドのコンテキストの中で行われるということです。
デバッグ・ツールが、主に症状の検出のタイミングとエラーの挿入のタイミングを近づけることに焦点をおいているのは、これらの理由によります。 これはアプリケーション開発者が、コードのどの部分がエラーを起こしている原因であるかをより正確にねらうのに役立ちます。
多くの異なったデバッグ・ツールが、malloc で使用するために開発されています。 他のデバッグ・ツールと組み合わせて、すべての割り当てポリシーで使用することができるものも、使用範囲がより限定されているものもあります。 多くのデバッグ・ツールは、プロセスが必要とするリソースの他に追加のリソースを使用します。 必要なときに適切なリソースを提供するのは、アプリケーション開発者の責任です。
パフォーマンスの考慮事項
malloc をデバッグするツールは、常時、持続的に使用したり、システム全体で使用したりするのには適していません。 これらは、デバッグする
アプリケーションへのパフォーマンスの影響を最小限に押さえるように設計されていますが、
システム全体の広い範囲で使用すると、システム全体のスループットに重大な悪影響を及ぼす場合があります。 特に、 /etc/environment ファイルに MALLOCDEBUG=catch_overflow を設定することはお勧めできません。これにより、ページング・スペースの過剰使用などの重大なシステム問題が発生する可能性があります。 malloc をデバッグするツールの使用は、一度に 1 つのアプリケーション、
あるいは、小さなアプリケーション・グループのデバッグに制限する必要があります。
malloc をデバッグするツールを使用可能にすると、 実行時にさまざまなチェックの処理が追加されるので、malloc サブシステムのパフォーマンスは (どのツールを使用するかに依存して) 可変で低下しますが、アプリケーションが作動しなくなるほどではありません。 問題が解決したら、malloc をデバッグするツールをオフにして、malloc サブシステムのパフォーマンスを復元させます。
ディスクとメモリーの考慮事項
catch_overflow または Malloc Log ツールを使用可能にすると、malloc サブシステムは非常に大量のメモリーを使用します。
catch_overflow では、各 malloc 要求は 4096 + (unsigned long のサイズの 2 倍) だけ増加し、PAGESIZE マクロの次の倍数に切り上げられます。 catch_overflow は、大変大きなアプリケーションで使用するにはメモリー集約的過ぎるということになるかもしれません。しかし、メモリー・デバッグを必要とする大半のアプリケーションに対しては、メモリーの追加使用は問題にはならないはずです。 大規模なアプリケーションでは、 debug_rangeオプションと functionsetオプションをcatch_overflowに使用すると、メモリ使用量が大幅に削減され、プログラムを段階的にデバッグできます。
Malloc Log では、プロセス内でアクティブなすべての割り当てに対して、割り当て記録が保管されます。 このためのメモリー・オーバーヘッドは、保管されるスタック・ポインターに小さい数値を指定することによって最小化することができます。
デバッグ中のアプリケーションが malloc サブシステムの割り当てルーチンを頻繁に呼び出すと、malloc をデバッグするツールを使用可能にしているためにメモリー使用上の問題が発生し、アプリケーションが単一セグメント内で正常に 実行されない場合があります。 この場合に有効なのは、ulimit コマンドおよび ld コマンドの -bmaxdata オプションを使用して、アプリケーションが追加のメモリーにアクセスできるようにすることです。
ulimit -d unlimited
ulimit -s unlimited 32 ビット・プロセス用の最大の 8 セグメントを予約するには、-bmaxdata オプションを -bmaxdata:0x80000000 と指定する必要があります。
malloc をデバッグするツールがオフの場合は、ulimit および -bmaxdata にはデフォルト値がリストアされます。
ulimit コマンドおよび -bmaxdata オプションについて詳しくは、 Large Program Supportを参照してください。
malloc をデバッグするツールは、デバッグする状態によっては使用するのが適切ではありません。 いくつかの malloc をデバッグするツールは、割り当てごとに 1 ページ以上のオーバーヘッドを必要とするので、 小さな割り当て要求をたくさん出すプログラムでは、メモリー使用量が急激に増加します。 これらのプログラムでは、 メモリーやページング・スペースの不足によってメモリー割り当て要求が拒否され、別の障害が発生する 場合があります。 これは必ずしもデバッグ中のプログラムで起こるエラーではなく、また malloc をデバッグするツールの エラーでもありません。
- catch_overflow をオフにして X サーバーを開始する。
- ターミナル・ウィンドウを開始する (例: dtterm、xterm、aixterm)。
- ターミナル・ウィンドウ・セッションで該当の環境変数を設定して、catch_overflow を使用可能にする。
- X クライアント・プログラムを起動し、同じウィンドウからデバッグする。
malloc のデバッグの使用可能化
Debug Malloc はデフォルトでは使用可能になりませんが、MALLOCDEBUG 環境変数を該当のオプションに設定することによって使用可能になり構成されます。 複数のオプションが必要な場合は、オプションをコンマ (,) で区切ることができます。 タンデムで要求されるオプションは、相互に互換性が必要です。
Malloc デバッグ・ツール
バッファー・オーバーフロー検出
メモリー管理エラーは、ときどきアプリケーション・プログラムが割り当てられたバッファーの終端を超えて書き込みを行うことによって起こることがあります。 これは、しばしば、すぐに結果がでるものではないので、 ずっと後に、上書きされた (通常は他に割り当てられている) メモリーが参照され、本来そこに保管されていたデータが含まれていなくなるまで、症状は現れません。
catch_overflow デバッグ・オプションがあるので、ユーザーは、メモリーの上書き、オーバーリード、重複メモリー解放、および malloc サブルーチンが割り当てた解放済みメモリーの再利用を識別することができます。 catch_overflow ツールが
検出したメモリーの問題は、abort 呼び出しまたはセグメンテーション違反 (SIGSEGV) の結果となります。 多くの場合、エラーが検出されると、アプリケーションはただちに停止し、コア・ファイルが作成されます。
catch_overflow オプションは、以下の割り当てポリシーおよびオプションの割り当てに影響を及ぼします。- デフォルト割り当てポリシー
- Watson 割り当てポリシー
- Malloc マルチヒープ・オプション
- Malloc スレッド・キャッシュ・オプション
- Malloc 特記オプション
catch_overflow デバッグ・オプションは、MALLOCDEBUG=catch_overflow を設定することによって使用可能にします。 これによりメモリー上書きおよびメモリー・オーバーリードの識別がオンになります。
- 位置合わせ
デフォルトでは、malloc サブルーチンは、2 ワード境界に位置合わせしたポインターを戻します。 これは標準への準拠のためと、位置合わせされていないメモリー・アクセスを受け付けることができないプログラム (例えば、DCE コンポーネントを使用するプログラム) のために必要です。 しかし、
catch_overflowオプションのインプリメンテーションが採用しているロジックのために、プログラムが、catch_overflowによって検出されることなしに、位置合わせ値より少ない量によってバッファーを上書きすることが起こり得ます。alignオプションを使用して、 malloc サブシステムに、検出されずにバッファーを上書きできるバイト数を減らすか除去するために、 このデフォルトの位置合わせを無視するように指示することができます。 カスタム位置合わせを 0 から 4096 (4096 も含む) までの間の 2 の累乗 (例えば、0、1、2、4、...、4096) で指定できます。 値 0 と 1 は同じものとして扱われます。すなわち、メモリーの位置合わせは行われません。したがって、割り当てられたエリアを越えるメモリー・アクセスは SEGFAULT を起こします。alignオプションはcatch_overflowオプションの一部であり、catch_overflowが使用可能である場合にのみ意味があります。 デフォルト以外の位置合わせを使用可能にするには、MALLOCDEBUG 環境変数を次のように設定します。
ここで、n は要求する位置合わせです。MALLOCDEBUG=catch_overflow,align:ncatch_overflowオプションが、ある割り当て要求に対して、何バイトまでのオーバーリードまたは上書きを許すかを計算するには、次の公式を使用します。ここで、n が要求する位置合わせで size が割り当てるバイト数です。((((size / n) + 1) * n) - size) % n次の例は、catch_overflow オプションが使用可能な場合の、アプリケーションがオーバーリードまたは上書きを実行する能力に関する align オプションの効果を説明しています。 この例では、align オプションで値 2 を指定しています。MALLOCDEBUG=align:2,catch_overflowcatch_overflowオプションは、オーバーリードおよび上書きを次のように処理します。- 偶数バイト数を割り当てる場合は、malloc は要求されたとおりのバイト数を割り当てますが、0 バイトのオーバーリードまたは上書きも許されます。
- 奇数バイト数を割り当てる場合は、malloc は要求されたバイト数に加えて、 必要な位置合わせができるように、追加の 1 バイトを割り当てます。 これは、1 バイトのオーバーリードまたは上書きを許します。
- シグナル処理の指定変更
catch_overflowオプションは、以下のいずれかの方法でエラーを報告します。- メモリー・アクセス・エラー (割り当てられたメモリーの終端を超えて書き込みや読み取りを行おうとした場合など) では、 セグメンテーション違反 (SIGSEGV) を発生させて、コア・ダンプを取ります。
- 他のタイプのエラー (既に解放されているスペースを解放しようとした場合など) では、
catch_overflowオプションは、エラー・メッセージを出力してから、abort 関数を呼び出して SIGIOT シグナルを送って現行のプロセスを終了させます。
呼び出し側プログラムが、SIGSEGV および SIGIOT シグナルをブロックしたり、キャッチしたりしている場合は、
catch_overflowオプションはエラーを報告することができません。override_signal_handlingオプションは、アプリケーションをコーディングし直したり、再ビルドしたりしないで、この状態をバイパスする手段を提供します。override_signal_handlingオプションが指定された場合は、catch_overflowオプションは、 malloc サブシステム・ルーチンへの呼び出しがあるたびに以下のアクションを実行します。- SIGSEGV または SIGIOT 用にアプリケーションが設定した既存のすべてのシグナル・ハンドラーを使用不可にする。
- SIGIOT および SIGSEGV の両方に対するアクションをデフォルト (SIG_DFL) に設定する。
- SIGIOT および SIGSEGV の両方を非ブロックにする。
アプリケーション・シグナル・ハンドラーがメモリー割り当てルーチンの呼び出しと呼び出しの間に SIGSEGV に対するアクションを変更して、 無効なメモリー・アクセスを行うと、catch_overflow オプションはエラーを報告することができません (アプリケーションは終了せず、コア・ファイルは作成されません)。
注:override_signal_handlingオプションは、スレッド化されたアプリケーション環境では効果がない場合があります。なぜなら、catch_overflowオプションは sigprocmask サブルーチンを使用し、多くのスレッド化されたプロセスは pthread_sigmask サブルーチンを使用するからです。- スレッドが、シグナル・セットに SIGSEGV と SIGIOT を組み込まないで sigwait サブルーチンを呼び出し、続いて
catch_overflowオプションがエラーを検出した場合は、catch_overflowオプションが SIGSEGV または SIGIOT だけしか生成できないので、そのスレッドはハングします。 - 無効なメモリーへのポインターがカーネル・ルーチンへ渡されると、カーネル・ルーチンは、 障害を起こし、通常、errno に EFAULT をセットして戻ります。 アプリケーションがシステム・コールからの戻りを検査していない場合、このエラーは 検出されない恐れがあります。
- デバッグ範囲
catch_overflowオプションが使用可能な場合は、バッファー・オーバーフロー検出が、デフォルトで、プログラムでのすべての割り当てに対して実行されます。debug_rangeオプションが指定されている場合は、ユーザー定義の最小と最大サイズ間に入る割り当て要求だけが、catch_overflowオプションによってバッファー・オーバーフローを検出されます。 それ以外の場合は、 バッファー・オーバーフロー検出は実行されません。 このオプションを使用して、ユーザーは、特定のケースではツールを使用するだけで、catch_overflowオプションが 使用する追加のメモリー・リソースの量を制御することができます。debug_rangeオプションは、catch_overflowオプションのコンテキスト内のみで意味があります。 これは次のようにして使用可能にします。
ここで、min はバッファー・オーバーフロー検出が実行される範囲の下限で、max はその上限です。 最小値として 0 が指定された場合は、最大値より小さいすべての要求でバッファー・オーバーフロー検出が実行されます。 最大値として 0 が指定された場合は、最小値より大きいすべての要求でバッファー・オーバーフロー検出が実行されます。MALLOCDEBUG=catch_overflow,debug_range:min:max制限: 内部実装要件のため、各割り振りの長さは、少なくとも 1 ページ・サイズにする必要があります。 したがって、
debug_rangeオプションは、それを除去するというよりむしろ、 単にcatch_overflowオプションのオーバーヘッドを減らすだけです。realloc サブルーチンが、ユーザー指定の範囲に入る割り当て要求で呼び出された場合は、たとえ元の割り当てが指定された範囲内になかったとしても、バッファー・オーバーフロー検出が実行されます。 その逆もまた真です。
注:override_signalオプションをdebug_rangeオプションと一緒に設定すると、SIGIOT および SIGSEGV シグナル動作のオーバーライドがすべての割り振りに対して実行されます。- 関数セット
内部のインプリメンテーションの必要によって、いまだに、各割り当ては必ず少なくとも 1 ページ・サイズの長さになります。 したがって、
functionsetオプションは、それを除去するというよりむしろ、 単にcatch_overflowオプションのオーバーヘッドを減らすだけです。realloc サブルーチンが、ユーザー指定の関数リストのメンバーの関数から呼び出された場合は、たとえ元の割り当てが指定された関数から行われていなかったとしても、バッファー・オーバーフロー検出が実行されます。 その逆もまた真です。
注:override_signalオプションをfunctionsetオプションと一緒に設定すると、SIGIOT および SIGSEGV シグナル動作のオーバーライドがすべての割り振りに対して実行されます。functionsetオプションは、リスト内に指定された関数の妥当性は検査しません。- オーバーリーディングを許可
デフォルトでは、
catch_overflowデバッグ・オプションが使用可能にされていて、呼び出し側プログラムが割り当てられたメモリーの終端を超えて読み取りを行った場合は、セグメンテーション違反が起こり、プロセスはコア・ダンプを取ります。 しかし、 ユーザーはこのタイプのエラーをキャッチすることには興味がなく、さらに危険な上書きをキャッチするために、catch_overflowを使用可能にさせることがあります。allow_overreadingオプションを指定することにより、catch_overflowオプションがオーバーリードを無視するようになり、さらに重大と考えられる他のタイプのエラーを最初に検出することができます。allow_overreadingオプションは、catch_overflowオプションのコンテキスト内のみで意味があります。 これは次のようにして使用可能にします。MALLOCDEBUG=catch_overflow,allow_overreading,- postfree_checking
postfree_checkingオプションは、大量の追加メモリーを使用します。 非常に大量のメモリーを必要とするプログラムは、postfree_checkingオプションを使用できない可能性があります。- Malloc trace
Malloc Trace は、システム・トレース機能を介して、malloc サブシステム API へのすべての呼び出しをトレースできるようにするために設計されたデバッグ・オプションです。
- マロー・ログ
Malloc Log は、malloc サブシステム内でアクティブな割り当ての実行時データベースを、 ユーザーに提供するために設計されたデバッグ・オプションです。
- report_allocations
report_allocationsオプションは、アプリケーション・プログラムでのメモリー・リークを検出するツールです。report_allocationsオプションは、Malloc Log によって構成されたデータベースを使用して、現在ユーザーが保持している割り当てのリストを報告します。 正常終了した各割り当てのレコードは、Malloc Log による要求時に作成されます。 割り当てが割り当て解除されると、Malloc Log はデータベースからそのレコードを除去します。 プロセスの終了時に、 まだアクティブな割り当てのリストは stderr に出力され、呼び出し元によって解放されなかった割り当てのリストが提供されます。report_allocationsオプションは、動作するために Malloc Log の機能を必要とします。 したがって、 Malloc Log は、report_allocationsが使用可能にされるとき、暗黙的に使用可能にされます。report_allocationsオプションは、 次のようにして使用可能にします。MALLOCDEBUG=report_allocations- validate_ptrs
デフォルトでは、malloc サブシステム API は、それらが事前に割り当てられたメモリーを実際に参照していることを確認するための、入力ポインターの妥当性検査は行いません。 これらのポインターのうちの 1 つが無効な場合、重大なヒープ破壊が起こることになります。
validate_ptrsオプションを指定すると、malloc サブシステム API は、入力ポインターの広範囲な妥当性検査を実行します。 ポインターが無効なことが分かった (すなわち、malloc サブシステム API の呼び出しによって事前に割り当てられたメモリーを参照していない) 場合、無効な理由を示したエラー・メッセージが表示され、abort 関数が呼び出され、コア・ファイルが作成されます。validate_ptrsオプションは、verboseサブオプションに似ています。postfree_checkingオプションが使用可能になっている場合、validate_ptrsオプションは有効になりません。validate_ptrsオプションは、次のようにして使用可能にします。MALLOCDEBUG=validate_ptrs- Malloc detect
Malloc Detect は、malloc サブシステム API のすべての呼び出しで、malloc サブシステムの内部データ構造の破壊を検出して報告するために設計されたデバッグ・オプションです。
- verbose
Malloc Detect のサブオプションです。
- チェッカーアリーナ
Malloc Detect のサブオプションです。
- 出力 (output)
デフォルトで、malloc デバッグ・オプションは出力を stderr に送ります。 これは、 すべてのプログラムにとっては望ましくないことがあります。
outputオプションを使用して、表示される情報の代替宛先を指定することができます。 出力は、stderr、stdout、またはシステム上の任意のファイルのいずれかに送られます。outputオプションは、次のようにして使用可能にします。MALLOCDEBUG=output:<filename>- 続く
多くの malloc デバッグ・オプションは、エラーを検出すると、abort() を呼び出します。 これは、必ずしもすべてのプログラムにとって望ましい動作とは限りません。
continueオプションを使用して、同期エラーの検出の後でプロセスを異常終了するのではなく続行するように、malloc サブシステムに指示することができます。 それでも、エラー・メッセージは該当のチャネルにログされます。continueオプションは、次のようにして使用可能にします。MALLOCDEBUG=continue- Malloc デバッグ充てん
malloc debug fill は、デバッグを目的として、malloc() 呼び出しによって割り当てられたメモリーをユーザー指定のパターンで満たすように設計されたデバッグ・オプションです。
パターンは文字列として指定する必要があり (例えば、export MALLOCDEBUG=fill:”abc” と指定すると、malloc によって割り当てられたメモリーがパターン “abc” で設定されます)、最大 128 文字を使用できます。 このパターンを指定しない場合、fill オプションは無視されます。
malloc debug fill オプションは、次のようにして使用可能にできます。
MALLOCDEBUG=fill:patternパターンは、ストリング形式で指定される 8 進数または 16 進数です。 すなわち、パターン “¥101” は文字「A」の 8 進表記として処理され、パターン “¥x41” は文字「A」の 16 進表記として処理されます。
無効な 8 進数が指定された場合、例えば、1 バイトに収まらない ¥777 などは、1 バイトとして保管できる最大 8 進値である ¥377 として保管されます。