mallocでメモリ破壊とか2重freeとかやらかしてそうな時のutraceの使い方のメモ
まず、libcのmalloc.cあたりを眺めてutraceを有効にする。「HAS_UTRACE」とかで#ifdef切ってあってたぶん無効になっているので、有効にしてコンパイル。
次に、mallocデバッグしたいプロセス側からmalloc_utraceを有効にする。/etc/malloc.confでuを設定しといたり、MALLOC_OPTIONS環境変数にu入れといたり、void utrace_on(int on);関数を呼んだり、mallocライブラリによってまちまちなようなので、自分の使ってるのに合わせて対応する。
(※ 個々のプロセスでonするという仕組みなのは、こうなっていないとlibc使う人全員がデバッグオプションONになっていろいろうざいため)
最後に、utrace関数を実装する。適当に
typedef struct {
void *a;
size_t b;
void *c;
void *d;
} rinchan_t;
int rinchan=0;
void *rinchan_a[10000];
void *rinchan_c[10000];
void *rinchan_d[10000];
int utrace(rinchan_t *arg, int size){
int idx = rinchan++;
rinchan_a[idx] = arg->a;
rinchan_c[idx] = arg->c;
rinchan_d[idx] = arg->d;
}
とかをmallocデバッグしたいプロセス側で定義する。
FreeBSDに入っている(?)dlmallocの場合はこのプロトタイプでOKだけど、なんかmallocライブラリによってutraceプロトタイプが違うみたいなんでそこは適当に。C言語が高級アセンブラな人からすれば、プロトタイプなんてただの飾りですよ。
これでgdbつなぎながら問題を起こして、そのときgdbからrinchanを見ることで、どんな風なmalloc/freeとそれがどこから呼ばれたかのトレースがだいたいできる。見た結果、mallocを呼んでるのがcallocだとわかった、とかならなかなか泣けるけど・・・
rinchan配列1万で十分なのかどうかについては、私がデバッグしたかったアプリでは十分だっただけなので、適時適当に。rinchanがオーバフローするとリン廃が歓喜するだけなのでそれがイヤなマゾな人は、shigoto++とかどうぞ。え?shigotoはインクリメントじゃなくてデクリメントしてくものだ? そ う 思 っ て い た 時 期 が 私 に も あ り ま し た 。 ぜひ、がんばればshigotoがデクリメントしてく職場を紹介してください・・・
utrace関数内でprintfしようとすると、printfからmalloc呼ばれてそこからutrace呼ばれて・・・のコンボに入って、「あれutraceの使い方間違ってんのかな?」と変に調べ物に入って1時間くらい損するので注意。損した人が言うんだから間違いない。
utraceはweakシンボルかなにかになっているようで、utrace関数を定義しなかったらしなかったなりに適当にやってくれるっぽい。
なにぶん、ソースコードを斜め読みしながら試しに作ってみて動かした程度なので、間違ってたらすいません、、