This library is designed to be a nice complement of valgrind and libduma (ex efence) to
detect leak memory. It simply override C/C++ allocation function (new, malloc, ...) to
keep then in a simple list that could be analysed later. The effective allocation is
still done by the underlying libc.
It can be used when valgrind is not ported on your platform, when libduma is using too
much virtual memory (embedded system), or when you're really interested in tracking only
memory leaks.
You may start/stop/dump monitoring allocation from the first allocation, when the program
receive a signal (for ex. SIGUSR1), or when you explicitly call a LeakTracer function.
/** starts monitoring memory allocations in all threads */
inline void startMonitoringAllThreads(void);
/** starts monitoring memory allocations in current thread */
inline void startMonitoringThisThread(void);
/** stops monitoring memory allocations (in all threads or in
* this thread only, depends on the function used to start
* monitoring */
inline void stopMonitoringAllocations(void);
/** stops all monitoring - both of allocations and releases */
inline void stopAllMonitoring(void);
/** writes report with all memory leaks */
void writeLeaksToFile(const char *reportFileName);
typedef struct {
/* Pathname of shared object that contains address. */
const char* dli_fname;
/* Address at which shared object is loaded. */
void* dli_fbase;
/* Name of nearest symbol with address lower than addr. */
const char* dli_sname;
/* Exact address of symbol named in dli_sname. */
void* dli_saddr;
} Dl_info;
typedef struct {
const char *symbname;
void *libcsymbol;
void **localredirect;
} libc_alloc_func_t;
static Dl_info s_P2pSODlInfo;
static libc_alloc_func_t libc_alloc_funcs[] = {
{ "calloc", (void*)__libc_calloc, (void**)(<_calloc) },
{ "malloc", (void*)__libc_malloc, (void**)(<_malloc) },
{ "realloc", (void*)__libc_realloc, (void**)(<_realloc) },
{ "free", (void*)__libc_free, (void**)(<_free) }
};
void MemoryTrace::init_no_alloc_allowed()
{
libc_alloc_func_t *curfunc;
unsigned i;
// 记录libc中需要重写的函数的地址
for (i=0; i<(sizeof(libc_alloc_funcs)/sizeof(libc_alloc_funcs[0])); ++i) {
curfunc = &libc_alloc_funcs[i];
if (!*curfunc->localredirect) {
if (curfunc->libcsymbol) {
*curfunc->localredirect = curfunc->libcsymbol;
} else {
*curfunc->localredirect = dlsym(RTLD_NEXT, curfunc->symbname);
}
}
}
// 调用一次dladdr,用于记录动态库加载时的基础偏移量
dladdr((const void*)init_no_alloc_allowed, &s_P2pSODlInfo);
__instance = reinterpret_cast<MemoryTrace*>(&s_memoryTrace_instance);
// we're using a c++ placement to initialized the MemoryTrace object living in the data section
new (__instance) MemoryTrace();
// it seems some implementation of pthread_key_create use malloc() internally (old linuxthreads)
// these are not supported yet
pthread_key_create(&__instance->__thread_internal_disabler_key, NULL);
}
inline void MemoryTrace::registerAllocation(void *p, size_t size, bool is_array) {
allocation_info_t *info = NULL;
if (!AllMonitoringIsDisabled() &&
(__monitoringAllThreads || getThreadOptions().monitoringAllocations) && p != NULL) {
MutexLock lock(__allocations_mutex);
info = __allocations.insert(p);
if (info != NULL) {
info->size = size;
info->isArray = is_array;
storeTimestamp(info->timestamp);
}
}
// we store the stack without locking __allocations_mutex
// it should be safe enough
// prevent a deadlock between backtrave function who are now using advanced dl_iterate_phdr function
// and dl_* functionwhich uses malloc functionsif (info != NULL) {
storeAllocationStack(info->allocStack);
}
if (p == NULL) {
InternalMonitoringDisablerThreadUp();
// WARNING
InternalMonitoringDisablerThreadDown();
}
}