ppt

メモリ関連エラーの追及, 性能プ
ロファイル
メモリ関連エラー

空間軸上の間違い
• 領域オーバーフロー
• Nバイト割り当てて, Nバイト目以降(Nバイト目を含む)を
触る
• ポインタの初期化し忘れ, ポインタ変数の破壊

時間軸上の間違い
• 早すぎる解放(free)
• 解放し忘れ(リーク)
領域オーバーフローの例
char * a = (char *)malloc(N); a[N] = …;
 char a[N]; a[N] = …;
 typedef struct foo { … } foo, * foo_t;
foo_t = (foo_t)malloc(sizeof(foo_t));
 char * s_copy = (char *)malloc(strlen(s));
strcpy(s_copy, s);

おきていること

mallocした領域の「ちょっと後ろ」に書き込む(
必ず「ちょっと」かどうかはわからないが, 割と
多くの場合「ちょっと」)
典型的症状

そこに何があるかで挙動は千差万別だが…
• mallocの場合, malloc自身の管理領域, 別の
mallocで割り当てた領域
• 将来のmalloc/free中にsegmentation fault
• 別の, mallocした領域を破壊
• 局所配列の場合, 別の変数
• 別の変数を破壊
• それがポインタなら将来そのポインタを通じてメモリを
アクセスしたときにsegmentation fault
• 「大幅に」はみ出せばアクセス不能領域
• segmentation fault
ポインタの初期化し忘れ, 破壊
char * a; a[0] = …
 foo * a = mk_foo();
…
foo * mk_foo() { returnし忘れ; }


症状: (aを通じてメモリをアクセスした際), まっ
たくでたらめなアドレスを参照しにいくことにな
る(segmentation fault, 変数の破壊)
はやすぎる解放

char * a = (char *) malloc(…);
free(a);
a[0] = …
 解放後, その領域が別のmallocによって割り
当てられ, その後aを通じてその領域に書き込
んだ際, その領域を破壊
メモリ関連エラーの厄介な点

間違った際の挙動は「不定」
• 領域はみ出し, 初期化し忘れなどで何が起こるか
は, プログラマの知らないmallocやスタックなどの
memoryレイアウトで決まる
• 症状
• 最適化を外したら「なぜか」動いた
• このメモリを1バイト余計に割り当てたら「なぜか」動い
た(これで正しい場合もあるが)

間違ってもすぐに症状が現れない
• 破壊した領域を使ったときに最終的な症状が現
れる
メモリ関連エラーの回避・デバッグ
ツール

GC
• 時間軸方向のエラーをなくす(freeを呼ばなくてよ
い)
• 空間軸方向のエラーには無力

MALLOC_CHECK_, valgrind
• 空間軸方向のエラーの一部を検出
MALLOC_CHECK_
朗報: 最近のLinuxのdefaultのmallocに組み
込まれている(installの必要なし)
 動作:

• mallocした領域を「ちょっと」踏み越えたアクセス
を検出
• いつ? malloc/free時に検出

環境変数MALLOC_CHECK_によって動作
を変えられる(cf. man malloc)
効果的な使い方
エラーが出るようになったら, -g でコンパイル
し, gdbで走らせる
 エラーがおきるとabort関数を呼び, gdb内で実
行が停止する
 gdbのupコマンドでエラーが起きた場所を突き
止める

制限
エラーがチェックされるのはmalloc/free時のみ
 「領域はみ出しアクセス」を行った瞬間ではない
 基本はmallocの管理領域の破壊を検出している
だけなので, malloc以外のメモリ領域のはみ出し
には無力
 mallocに限ってもすべての領域はみ出しが検出
されるわけではなく, 実際カバー率は低い

valgrind
(Ubuntu) apt-get install valgrind
 それ以外の場合, Googleで検索


-gでコンパイルしたプログラムを,
valgrind <コマンド>
で実行するだけ
valgrind

プログラムをその場で書き換えて実行する(
個々のメモリアクセスを監視)ため,
• 「領域はみ出しの瞬間」を検出できる
• 検出力(カバー率)が高い

制限:
• おそい
そのほか
常に最大限の警告を出すオプション(gccであ
れば –Wall)をつけてコンパイル
 警告を無視しない

性能プロファイル
gcc –pg … (コンパイル時とリンク時の両方)
 ./minipy … (実行)
 “gmon.out”というファイルが出来る
 gprof minipy で結果を表示
