toge's diary

コンピュータ関連の趣味をつらつらと。

[C++]mudflapを訳してみる

せっかくの機能なのになかなか使われないみたいですね。便利なのに。
googleで"mudflap gcc"と指定してもあんまり情報がないのが残念です。

少しでも普及するように、以下のmudflap記事を適当に訳してみました。

http://gcc.gnu.org/wiki/Mudflap%20Pointer%20Debugging

mudflapでのポインタデバッグ

コンパイラに-fmudflapに指定することで有効になります。

C, C++のようにmudflapをサポートしているフロントエンドの場合、
全てのリスキーな以下の内容を範囲と有効性のテストで検出できます。

  • ポインタ・配列の参照操作
  • いくつかの標準ライブラリの文字とヒープ操作関数
  • その他の関連する構造

そのためmudflapを指定したモジュールはバッファーオーバーフロー、不正なヒープ使用、その他のC/C++プログラミングエラーの影響を受けなくなります。

mudflapの機能は独立したランタイムライブラリ(libmudflap)に依存しています。

このライブラリはリンク時に-fmudflap -lmudflapと指定することでプログラムにリンクします。

mudflapを指定したプログラムの振舞いはMUDFLAP_OPTIONS環境変数で制御できます。

実際のオプションのリスト得るためには、MUDFLAP_OPTIONSに-helpを指定して、対象となるプログラムを実行します。

現在以下のような出力になります。

mudflapコードは環境変数で制御できます。

$ export MUDFLAP_OPTIONS=''
$

は以下のオプションをスペースで区切ったリストになります。
無効にするには-no-OPTIONとします。

  • mode-nop mudflapsは何もしません
  • mode-populate mudflapsはオブジェクト木を構築します
  • mode-check mudflapsはメモリ汚染をチェックします(有効)
  • mode-violate mudflapsは常に違反を起こします(診断)
  • viol-nop 汚染時にプログラムの実行を変更しません(有効)
  • viol-abort 汚染時にabort()を呼び出します
  • viol-segv SIGSEGVシグナルが汚染を引き起こします
  • viol-gdb 汚染時に現在のプログラムにアタッチしたgdbプログラムをフォークします
  • trace-calls traceはmudflapランタイムライブラリを呼び出します
  • verbose-trace mudflapのランタイムライブラリの内部イベントを追跡します
  • collect-stats mudflap操作の分析を収集します
  • sigusr1-report SIGUSR1時に報告を表示します
  • internal-checking より高価な内部チェックを行います
  • print-leaks プログラム終了時に全てのメモリーリークを表示します
  • check-initialization 非初期化オブジェクトの読み混みを検出します
  • verbose-violations メモリ汚染が起こった場合には冗長なメッセージを表示します(有効)
  • abbreviate abbreviate repetitive listings (active)
  • timestamps オブジェクトのライフタイムのタイムスタンプを追跡します(有効)
  • ignore-reads 読み混みアクセスを無視します(assume okay)
  • wipe-stack unwind時にスタックオブジェクトを消去します
  • wipe-heap free時にヒープオブジェクトの消去します
  • heur-proc-map /proc/self/map heuristicsを提供します
  • heur-stack-bound 単純なupper stack bound heuristicを提供します
  • heur-start-end _start.._end heuristicsを提供します
  • heur-stdlib 標準ライブラリデータ(argv, errno, stdin, ...)を登録する (有効)
  • free-queue-length=N queue N deferred free() calls before performing them (4)
  • persistent-count=N N個の非登録の領域の履歴を保持する(100)
  • crumple-zone=N surround allocations with crumple zones of N bytes (32)
  • lc-adapt=N N回キャッシュミスの跡でmask/shiftパラメータを適用する(1000003)
  • backtrace=N 各呼び出しコンテキストのNレベルのスタックとレースを保持する(4)
  • thread-stack=N スレッドスタック割当てをNkbに指定します(0)

マルチスレッドプログラム

プログラムがマルチスレッドの場合にはコンパイル時に-fmudflapのかわりに-fmudflapthを、リンク時に-fmuldflapth -lmudflapthを指定して下さい。

ポインタ読み込みを無視する

ポインタ読み込みを無視する場合には-fmudflapもしくは-fmudflapthに加えて-fmudflapirを指定して下さい。

このオプションは検出を弱くします(それゆえより高速に動作します)。
そしてあからさまなメモリ破壊書き込みに対する保護を提供します。
しかし誤ったデータ読みこみを許してしまいます。

既知の欠点

Frank EiglerとChris Scottがとりかわしたメール(参照先)によって明らかになったように、現段階のmudflapはプログラムのミスを隠す、データ構造にパディングを挿入しません。(訳注:ちょっとうまく訳せません)

以下の例を見て下さい。

int a[1024];
int b[1024];

[...]
int *i;
for (i = &b[0] ; i < &a[1024] ; i++)
*i = 0;
[...]

現在mudflapはbからaへの推移を検出しません。
なぜならmudflapは独立したポインタ参照が有効なオブジェクトを差し示しているかどうかを確認しているだけだからです。

この問題に対するmudflapの簡単な改良は、適切なstatic(もしくはautoでさえも)オブジェクトに対してパディングを挿入することです。
そしてこのパディング領域をアクセス不可能に設定します。
この方法で単純なイテレーションパターンを検出できます。