定義全域變數來紀錄: int malloc_count = 0, free_count = 0;
透過巨集 #define MALLOC(x) do { if (malloc(x)) malloc_count++; } while (0)
這有什麼問題?
要徹底解決這問題,其實就需要理解動態連結器 (dynamic linker) 的協助
以 GNU/Linux 搭配 glibc 為例
File: malloc_count.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
void* malloc(size_t size)
{
char buf[32];
static void* (*real_malloc)(size_t) = NULL;
if (real_malloc == NULL) {
*(void **)(&real_malloc) = dlsym(RTLD_NEXT, "malloc");
}
sprintf(buf, "malloc called, size = %zu\n", size);
write(2, buf, strlen(buf));
return real_malloc(size);
}
$ gcc -D_GNU_SOURCE -shared -fPIC -o /tmp/libmcount.so malloc_count.c -ldl
$ LD_PRELOAD=/tmp/libmcount.so ls
即可得知每次 malloc()
呼叫對應的參數,甚至可以統計記憶體配置,完全不需要變更原始程式碼。這樣的技巧,我們稱為 interpositioning。可能的應用是遊戲破解, 執行時期追蹤, sandboxing / software fault isolation (SFI), profiling,或者效能最佳化的函式庫 (如 TCMalloc)。
透過設定 LD_PRELOAD 環境變數,glibc 的 dynamic linker (ld-linux.so) 會在載入和重定位 (relocation) libc.so 之前,載入我們撰寫的 /tmp/libmcount.so 動態連結函式庫,如此一來,我們實做的 malloc 就會在 libc.so 提供的 malloc 函式之前被載入。當然,我們還是需要「真正的」 malloc,否則無法發揮作用,所以透過 dlsym 去從 libc.so 載入 malloc 程式碼,這裡 RTLD_NEXT 參數告知動態連結器,我們想從下一個載入的動態函式庫載入 malloc 的程式碼位址。
-Bsymbolic-functions
會影響 LD_PRELOAD 的行為