貧乏人の解決策は、すべての呼び出しmalloc
をfree
ログに記録してから、ログを調べてパターンを探すことです。
ld
ここで役立つ可能性のある素晴らしい機能を提供します。
--wrap=symbol
シンボルのラッパー関数を使用します。シンボルへの未定義の参照は、「__wrap_symbol」に解決されます。「__real_symbol」への未定義の参照はすべてsymbolに解決されます。
これは、システム関数のラッパーを提供するために使用できます。ラッパー関数は「__wrap_symbol」と呼ばれる必要があります。システム関数を呼び出したい場合は、「__real_symbol」を呼び出す必要があります。
簡単な例を次に示します。
void *
__wrap_malloc (size_t c)
{
printf ("malloc called with %zu\n", c);
return __real_malloc (c);
}
--wrap mallocを使用して他のコードをこのファイルにリンクすると、「malloc」へのすべての呼び出しは、代わりに関数「__wrap_malloc」を呼び出します。「__wrap_malloc」で「__real_malloc」を呼び出すと、実際の「malloc」関数が呼び出されます。
--wrapオプションのないリンクが成功するように、「__real_malloc」関数も提供することをお勧めします。これを行う場合は、「__real_malloc」の定義を「__wrap_malloc」と同じファイルに入れないでください。そうした場合、リンカが呼び出しを「malloc」にラップする前に、アセンブラが呼び出しを解決する可能性があります。
アップデート
これがどのように役立つかを明確にするためだけに。
- Upstartのビルドにカスタムファイルを追加します。
このような:
void*__wrap_malloc( size_t c )
{
void *malloced = __real_malloc(c);
/* log malloced with its associated backtrace*/
/* something like: <malloced>: <bt-symbol-1>, <bt-symbol-2>, .. */
return malloced
}
void __wrap_free( void* addr )
{
/* log addr with its associated backtrace*/
/* something like: <addr>: <bt-symbol-1>, <bt-symbol-2>, .. */
__real_free(addr);
}
upstartをデバッグシンボル(-g
)で再コンパイルして、いくつかの優れたバックトレースを取得できるようにします。-O2/-O3
必要に応じて、コードを最適化()することもできます。
Upstartを追加の、とリンクしLD_FLAGS
--wrap=malloc
ます--wrap=free
。
これで、 Upstartが呼び出す場所ならどこでもmalloc
、シンボルは魔法のように新しいシンボルに解決されます__wrap_malloc
。美しく、これはリンク時に発生するため、コンパイルされたコードに対してすべて透過的です。それは、混乱のないシミングやインストルメンテーション
のようなものです。
リークが発生したことを確認するまで、通常どおり再コンパイルされたUpstartを実行します。
malloced
ログを調べて、 sとsの不一致を探しaddr
ます。
いくつかのメモ:
- この
--wrap=symbol
機能は、実際にはマクロである関数名では機能しません。だから気をつけろ#define malloc nih_malloc
。これは、libnihを使用する必要があるもの--wrap=nih_malloc
であり、__wrap_nih_malloc
代わりに使用する必要があります。
- gccの組み込みのバックトレース機能を使用します。
- これらの変更はすべて、再コンパイルされたUpstart実行可能ファイルにのみ影響します。
- 代わりにログをsqliteDBにダンプすると、不一致のmallocとfreeを簡単に見つけることができます。
- SQL挿入ステートメントをログ形式にして、後で分析するためにデータベースに挿入することができます。