leak-detective: override malloc functions instead of using deprecated hooks
malloc hooks have become deprecated, and their use has always been problematic, especially in multi-threaded applications. Replace the functionality by overriding all malloc functions and query the system allocator functions using dlsym() with RTLD_NEXT.
This commit is contained in:
parent
e9b3bd5434
commit
17211b6b9a
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2006-2008 Martin Willi
|
* Copyright (C) 2013 Tobias Brunner
|
||||||
|
* Copyright (C) 2006-2013 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -14,20 +15,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <sched.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <malloc.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include "leak_detective.h"
|
#include "leak_detective.h"
|
||||||
|
|
||||||
|
@ -35,6 +34,8 @@
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/backtrace.h>
|
#include <utils/backtrace.h>
|
||||||
#include <collections/hashtable.h>
|
#include <collections/hashtable.h>
|
||||||
|
#include <threading/thread_value.h>
|
||||||
|
#include <threading/spinlock.h>
|
||||||
|
|
||||||
typedef struct private_leak_detective_t private_leak_detective_t;
|
typedef struct private_leak_detective_t private_leak_detective_t;
|
||||||
|
|
||||||
|
@ -69,17 +70,6 @@ struct private_leak_detective_t {
|
||||||
*/
|
*/
|
||||||
#define MEMORY_ALLOC_PATTERN 0xEE
|
#define MEMORY_ALLOC_PATTERN 0xEE
|
||||||
|
|
||||||
|
|
||||||
static void install_hooks(void);
|
|
||||||
static void uninstall_hooks(void);
|
|
||||||
static void *malloc_hook(size_t, const void *);
|
|
||||||
static void *realloc_hook(void *, size_t, const void *);
|
|
||||||
static void free_hook(void*, const void *);
|
|
||||||
|
|
||||||
void *(*old_malloc_hook)(size_t, const void *);
|
|
||||||
void *(*old_realloc_hook)(void *, size_t, const void *);
|
|
||||||
void (*old_free_hook)(void*, const void *);
|
|
||||||
|
|
||||||
static u_int count_malloc = 0;
|
static u_int count_malloc = 0;
|
||||||
static u_int count_free = 0;
|
static u_int count_free = 0;
|
||||||
static u_int count_realloc = 0;
|
static u_int count_realloc = 0;
|
||||||
|
@ -136,47 +126,146 @@ struct memory_tail_t {
|
||||||
* the others on it...
|
* the others on it...
|
||||||
*/
|
*/
|
||||||
static memory_header_t first_header = {
|
static memory_header_t first_header = {
|
||||||
magic: MEMORY_HEADER_MAGIC,
|
.magic = MEMORY_HEADER_MAGIC,
|
||||||
bytes: 0,
|
|
||||||
backtrace: NULL,
|
|
||||||
previous: NULL,
|
|
||||||
next: NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* are the hooks currently installed?
|
* Spinlock to access header linked list
|
||||||
*/
|
*/
|
||||||
static bool installed = FALSE;
|
static spinlock_t *lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is leak detection currently enabled?
|
||||||
|
*/
|
||||||
|
static bool enabled = FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is leak detection disabled for the current thread?
|
||||||
|
*/
|
||||||
|
static thread_value_t *thread_disabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs the malloc hooks, enables leak detection
|
* Installs the malloc hooks, enables leak detection
|
||||||
*/
|
*/
|
||||||
static void install_hooks()
|
static void enable_leak_detective()
|
||||||
{
|
{
|
||||||
if (!installed)
|
enabled = TRUE;
|
||||||
{
|
|
||||||
old_malloc_hook = __malloc_hook;
|
|
||||||
old_realloc_hook = __realloc_hook;
|
|
||||||
old_free_hook = __free_hook;
|
|
||||||
__malloc_hook = malloc_hook;
|
|
||||||
__realloc_hook = realloc_hook;
|
|
||||||
__free_hook = free_hook;
|
|
||||||
installed = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninstalls the malloc hooks, disables leak detection
|
* Uninstalls the malloc hooks, disables leak detection
|
||||||
*/
|
*/
|
||||||
static void uninstall_hooks()
|
static void disable_leak_detective()
|
||||||
{
|
{
|
||||||
if (installed)
|
enabled = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable leak detective for the current thread
|
||||||
|
*
|
||||||
|
* @return Previous value
|
||||||
|
*/
|
||||||
|
static bool enable_thread(bool enable)
|
||||||
|
{
|
||||||
|
bool before;
|
||||||
|
|
||||||
|
before = thread_disabled->get(thread_disabled) == NULL;
|
||||||
|
thread_disabled->set(thread_disabled, enable ? NULL : (void*)TRUE);
|
||||||
|
return before;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dlsym() might do a malloc(), but we can't do one before we get the malloc()
|
||||||
|
* function pointer. Use this minimalistic malloc implementation instead.
|
||||||
|
*/
|
||||||
|
static void* malloc_for_dlsym(size_t size)
|
||||||
|
{
|
||||||
|
static char buf[1024] = {};
|
||||||
|
static size_t used = 0;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
/* roundup to a multiple of 32 */
|
||||||
|
size = (size - 1) / 32 * 32 + 32;
|
||||||
|
|
||||||
|
if (used + size > sizeof(buf))
|
||||||
{
|
{
|
||||||
__malloc_hook = old_malloc_hook;
|
return NULL;
|
||||||
__free_hook = old_free_hook;
|
|
||||||
__realloc_hook = old_realloc_hook;
|
|
||||||
installed = FALSE;
|
|
||||||
}
|
}
|
||||||
|
ptr = buf + used;
|
||||||
|
used += size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a malloc function, while disabling wrappers
|
||||||
|
*/
|
||||||
|
static void* get_malloc_fn(char *name)
|
||||||
|
{
|
||||||
|
bool before = FALSE;
|
||||||
|
void *fn;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
before = enable_thread(FALSE);
|
||||||
|
}
|
||||||
|
fn = dlsym(RTLD_NEXT, name);
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
enable_thread(before);
|
||||||
|
}
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call original malloc()
|
||||||
|
*/
|
||||||
|
static void* real_malloc(size_t size)
|
||||||
|
{
|
||||||
|
static void* (*fn)(size_t size);
|
||||||
|
static int recursive = 0;
|
||||||
|
|
||||||
|
if (!fn)
|
||||||
|
{
|
||||||
|
/* checking recursiveness should actually be thread-specific. But as
|
||||||
|
* it is very likely that the first allocation is done before we go
|
||||||
|
* multi-threaded, we keep it simple. */
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
return malloc_for_dlsym(size);
|
||||||
|
}
|
||||||
|
recursive++;
|
||||||
|
fn = get_malloc_fn("malloc");
|
||||||
|
recursive--;
|
||||||
|
}
|
||||||
|
return fn(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call original free()
|
||||||
|
*/
|
||||||
|
static void real_free(void *ptr)
|
||||||
|
{
|
||||||
|
static void (*fn)(void *ptr);
|
||||||
|
|
||||||
|
if (!fn)
|
||||||
|
{
|
||||||
|
fn = get_malloc_fn("free");
|
||||||
|
}
|
||||||
|
return fn(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call original realloc()
|
||||||
|
*/
|
||||||
|
static void* real_realloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
static void* (*fn)(void *ptr, size_t size);
|
||||||
|
|
||||||
|
if (!fn)
|
||||||
|
{
|
||||||
|
fn = get_malloc_fn("realloc");
|
||||||
|
}
|
||||||
|
return fn(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -323,11 +412,13 @@ static int print_traces(private_leak_detective_t *this,
|
||||||
/** number of allocations */
|
/** number of allocations */
|
||||||
u_int count;
|
u_int count;
|
||||||
} *entry;
|
} *entry;
|
||||||
|
bool before;
|
||||||
|
|
||||||
uninstall_hooks();
|
before = enable_thread(FALSE);
|
||||||
|
|
||||||
entries = hashtable_create((hashtable_hash_t)hash,
|
entries = hashtable_create((hashtable_hash_t)hash,
|
||||||
(hashtable_equals_t)equals, 1024);
|
(hashtable_equals_t)equals, 1024);
|
||||||
|
lock->lock(lock);
|
||||||
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
||||||
{
|
{
|
||||||
if (whitelisted &&
|
if (whitelisted &&
|
||||||
|
@ -354,6 +445,7 @@ static int print_traces(private_leak_detective_t *this,
|
||||||
}
|
}
|
||||||
leaks++;
|
leaks++;
|
||||||
}
|
}
|
||||||
|
lock->unlock(lock);
|
||||||
enumerator = entries->create_enumerator(entries);
|
enumerator = entries->create_enumerator(entries);
|
||||||
while (enumerator->enumerate(enumerator, NULL, &entry))
|
while (enumerator->enumerate(enumerator, NULL, &entry))
|
||||||
{
|
{
|
||||||
|
@ -368,7 +460,7 @@ static int print_traces(private_leak_detective_t *this,
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
entries->destroy(entries);
|
entries->destroy(entries);
|
||||||
|
|
||||||
install_hooks();
|
enable_thread(before);
|
||||||
return leaks;
|
return leaks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,85 +495,66 @@ METHOD(leak_detective_t, report, void,
|
||||||
METHOD(leak_detective_t, set_state, bool,
|
METHOD(leak_detective_t, set_state, bool,
|
||||||
private_leak_detective_t *this, bool enable)
|
private_leak_detective_t *this, bool enable)
|
||||||
{
|
{
|
||||||
static struct sched_param oldparams;
|
if (enable == enabled)
|
||||||
static int oldpolicy;
|
|
||||||
struct sched_param params;
|
|
||||||
pthread_t thread_id;
|
|
||||||
|
|
||||||
if (enable == installed)
|
|
||||||
{
|
{
|
||||||
return installed;
|
return enabled;
|
||||||
}
|
}
|
||||||
thread_id = pthread_self();
|
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
install_hooks();
|
enable_leak_detective();
|
||||||
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
disable_leak_detective();
|
||||||
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
||||||
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
|
||||||
uninstall_hooks();
|
|
||||||
}
|
}
|
||||||
installed = enable;
|
return !enabled;
|
||||||
return !installed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(leak_detective_t, usage, void,
|
METHOD(leak_detective_t, usage, void,
|
||||||
private_leak_detective_t *this, FILE *out)
|
private_leak_detective_t *this, FILE *out)
|
||||||
{
|
{
|
||||||
int oldpolicy, thresh;
|
|
||||||
bool detailed;
|
bool detailed;
|
||||||
pthread_t thread_id = pthread_self();
|
int thresh;
|
||||||
struct sched_param oldparams, params;
|
|
||||||
|
|
||||||
thresh = lib->settings->get_int(lib->settings,
|
thresh = lib->settings->get_int(lib->settings,
|
||||||
"libstrongswan.leak_detective.usage_threshold", 10240);
|
"libstrongswan.leak_detective.usage_threshold", 10240);
|
||||||
detailed = lib->settings->get_bool(lib->settings,
|
detailed = lib->settings->get_bool(lib->settings,
|
||||||
"libstrongswan.leak_detective.detailed", TRUE);
|
"libstrongswan.leak_detective.detailed", TRUE);
|
||||||
|
|
||||||
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
|
||||||
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
||||||
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
|
||||||
|
|
||||||
print_traces(this, out, thresh, detailed, NULL);
|
print_traces(this, out, thresh, detailed, NULL);
|
||||||
|
|
||||||
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook function for malloc()
|
* Wrapped malloc() function
|
||||||
*/
|
*/
|
||||||
void *malloc_hook(size_t bytes, const void *caller)
|
void* malloc(size_t bytes)
|
||||||
{
|
{
|
||||||
memory_header_t *hdr;
|
memory_header_t *hdr;
|
||||||
memory_tail_t *tail;
|
memory_tail_t *tail;
|
||||||
pthread_t thread_id = pthread_self();
|
bool before;
|
||||||
int oldpolicy;
|
|
||||||
struct sched_param oldparams, params;
|
|
||||||
|
|
||||||
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
if (!enabled || thread_disabled->get(thread_disabled))
|
||||||
|
{
|
||||||
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
return real_malloc(bytes);
|
||||||
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
}
|
||||||
|
|
||||||
count_malloc++;
|
count_malloc++;
|
||||||
uninstall_hooks();
|
hdr = real_malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
|
||||||
hdr = malloc(sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
|
|
||||||
tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
|
tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
|
||||||
/* set to something which causes crashes */
|
/* set to something which causes crashes */
|
||||||
memset(hdr, MEMORY_ALLOC_PATTERN,
|
memset(hdr, MEMORY_ALLOC_PATTERN,
|
||||||
sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
|
sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
|
||||||
|
|
||||||
|
before = enable_thread(FALSE);
|
||||||
|
hdr->backtrace = backtrace_create(2);
|
||||||
|
enable_thread(before);
|
||||||
|
|
||||||
hdr->magic = MEMORY_HEADER_MAGIC;
|
hdr->magic = MEMORY_HEADER_MAGIC;
|
||||||
hdr->bytes = bytes;
|
hdr->bytes = bytes;
|
||||||
hdr->backtrace = backtrace_create(2);
|
|
||||||
tail->magic = MEMORY_TAIL_MAGIC;
|
tail->magic = MEMORY_TAIL_MAGIC;
|
||||||
install_hooks();
|
|
||||||
|
|
||||||
/* insert at the beginning of the list */
|
/* insert at the beginning of the list */
|
||||||
|
lock->lock(lock);
|
||||||
hdr->next = first_header.next;
|
hdr->next = first_header.next;
|
||||||
if (hdr->next)
|
if (hdr->next)
|
||||||
{
|
{
|
||||||
|
@ -489,25 +562,40 @@ void *malloc_hook(size_t bytes, const void *caller)
|
||||||
}
|
}
|
||||||
hdr->previous = &first_header;
|
hdr->previous = &first_header;
|
||||||
first_header.next = hdr;
|
first_header.next = hdr;
|
||||||
|
lock->unlock(lock);
|
||||||
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
|
||||||
|
|
||||||
return hdr + 1;
|
return hdr + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook function for free()
|
* Wrapped calloc() function
|
||||||
*/
|
*/
|
||||||
void free_hook(void *ptr, const void *caller)
|
void* calloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
size *= nmemb;
|
||||||
|
ptr = malloc(size);
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapped free() function
|
||||||
|
*/
|
||||||
|
void free(void *ptr)
|
||||||
{
|
{
|
||||||
memory_header_t *hdr, *current;
|
memory_header_t *hdr, *current;
|
||||||
memory_tail_t *tail;
|
memory_tail_t *tail;
|
||||||
backtrace_t *backtrace;
|
backtrace_t *backtrace;
|
||||||
pthread_t thread_id = pthread_self();
|
bool found = FALSE, before;
|
||||||
int oldpolicy;
|
|
||||||
struct sched_param oldparams, params;
|
|
||||||
bool found = FALSE;
|
|
||||||
|
|
||||||
|
if (!enabled || thread_disabled->get(thread_disabled))
|
||||||
|
{
|
||||||
|
real_free(ptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* allow freeing of NULL */
|
/* allow freeing of NULL */
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
|
@ -516,16 +604,12 @@ void free_hook(void *ptr, const void *caller)
|
||||||
hdr = ptr - sizeof(memory_header_t);
|
hdr = ptr - sizeof(memory_header_t);
|
||||||
tail = ptr + hdr->bytes;
|
tail = ptr + hdr->bytes;
|
||||||
|
|
||||||
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
|
||||||
|
|
||||||
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
||||||
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
|
||||||
|
|
||||||
count_free++;
|
count_free++;
|
||||||
uninstall_hooks();
|
before = enable_thread(FALSE);
|
||||||
if (hdr->magic != MEMORY_HEADER_MAGIC ||
|
if (hdr->magic != MEMORY_HEADER_MAGIC ||
|
||||||
tail->magic != MEMORY_TAIL_MAGIC)
|
tail->magic != MEMORY_TAIL_MAGIC)
|
||||||
{
|
{
|
||||||
|
lock->lock(lock);
|
||||||
for (current = &first_header; current != NULL; current = current->next)
|
for (current = &first_header; current != NULL; current = current->next)
|
||||||
{
|
{
|
||||||
if (current == hdr)
|
if (current == hdr)
|
||||||
|
@ -534,6 +618,7 @@ void free_hook(void *ptr, const void *caller)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock->unlock(lock);
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
/* memory was allocated by our hooks but is corrupted */
|
/* memory was allocated by our hooks but is corrupted */
|
||||||
|
@ -544,7 +629,7 @@ void free_hook(void *ptr, const void *caller)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* memory was not allocated by our hooks */
|
/* memory was not allocated by our hooks */
|
||||||
fprintf(stderr, "freeing invalid memory (%p)", ptr);
|
fprintf(stderr, "freeing invalid memory (%p)\n", ptr);
|
||||||
}
|
}
|
||||||
backtrace = backtrace_create(2);
|
backtrace = backtrace_create(2);
|
||||||
backtrace->log(backtrace, stderr, TRUE);
|
backtrace->log(backtrace, stderr, TRUE);
|
||||||
|
@ -553,52 +638,49 @@ void free_hook(void *ptr, const void *caller)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* remove item from list */
|
/* remove item from list */
|
||||||
|
lock->lock(lock);
|
||||||
if (hdr->next)
|
if (hdr->next)
|
||||||
{
|
{
|
||||||
hdr->next->previous = hdr->previous;
|
hdr->next->previous = hdr->previous;
|
||||||
}
|
}
|
||||||
hdr->previous->next = hdr->next;
|
hdr->previous->next = hdr->next;
|
||||||
|
lock->unlock(lock);
|
||||||
|
|
||||||
hdr->backtrace->destroy(hdr->backtrace);
|
hdr->backtrace->destroy(hdr->backtrace);
|
||||||
|
|
||||||
/* clear MAGIC, set mem to something remarkable */
|
/* clear MAGIC, set mem to something remarkable */
|
||||||
memset(hdr, MEMORY_FREE_PATTERN,
|
memset(hdr, MEMORY_FREE_PATTERN,
|
||||||
sizeof(memory_header_t) + hdr->bytes + sizeof(memory_tail_t));
|
sizeof(memory_header_t) + hdr->bytes + sizeof(memory_tail_t));
|
||||||
|
|
||||||
free(hdr);
|
real_free(hdr);
|
||||||
}
|
}
|
||||||
|
enable_thread(before);
|
||||||
install_hooks();
|
|
||||||
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook function for realloc()
|
* Wrapped realloc() function
|
||||||
*/
|
*/
|
||||||
void *realloc_hook(void *old, size_t bytes, const void *caller)
|
void* realloc(void *old, size_t bytes)
|
||||||
{
|
{
|
||||||
memory_header_t *hdr;
|
memory_header_t *hdr;
|
||||||
memory_tail_t *tail;
|
memory_tail_t *tail;
|
||||||
backtrace_t *backtrace;
|
backtrace_t *backtrace;
|
||||||
pthread_t thread_id = pthread_self();
|
bool before;
|
||||||
int oldpolicy;
|
|
||||||
struct sched_param oldparams, params;
|
|
||||||
|
|
||||||
|
if (!enabled || thread_disabled->get(thread_disabled))
|
||||||
|
{
|
||||||
|
return real_realloc(old, bytes);
|
||||||
|
}
|
||||||
/* allow reallocation of NULL */
|
/* allow reallocation of NULL */
|
||||||
if (old == NULL)
|
if (old == NULL)
|
||||||
{
|
{
|
||||||
return malloc_hook(bytes, caller);
|
return malloc(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr = old - sizeof(memory_header_t);
|
hdr = old - sizeof(memory_header_t);
|
||||||
tail = old + hdr->bytes;
|
tail = old + hdr->bytes;
|
||||||
|
|
||||||
pthread_getschedparam(thread_id, &oldpolicy, &oldparams);
|
|
||||||
|
|
||||||
params.__sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
||||||
pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms);
|
|
||||||
|
|
||||||
count_realloc++;
|
count_realloc++;
|
||||||
uninstall_hooks();
|
|
||||||
if (hdr->magic != MEMORY_HEADER_MAGIC ||
|
if (hdr->magic != MEMORY_HEADER_MAGIC ||
|
||||||
tail->magic != MEMORY_TAIL_MAGIC)
|
tail->magic != MEMORY_TAIL_MAGIC)
|
||||||
{
|
{
|
||||||
|
@ -613,33 +695,37 @@ void *realloc_hook(void *old, size_t bytes, const void *caller)
|
||||||
/* clear tail magic, allocate, set tail magic */
|
/* clear tail magic, allocate, set tail magic */
|
||||||
memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
|
memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic));
|
||||||
}
|
}
|
||||||
hdr = realloc(hdr, sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
|
hdr = real_realloc(hdr,
|
||||||
|
sizeof(memory_header_t) + bytes + sizeof(memory_tail_t));
|
||||||
tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
|
tail = ((void*)hdr) + bytes + sizeof(memory_header_t);
|
||||||
tail->magic = MEMORY_TAIL_MAGIC;
|
tail->magic = MEMORY_TAIL_MAGIC;
|
||||||
|
|
||||||
/* update statistics */
|
/* update statistics */
|
||||||
hdr->bytes = bytes;
|
hdr->bytes = bytes;
|
||||||
|
|
||||||
|
before = enable_thread(FALSE);
|
||||||
hdr->backtrace->destroy(hdr->backtrace);
|
hdr->backtrace->destroy(hdr->backtrace);
|
||||||
hdr->backtrace = backtrace_create(2);
|
hdr->backtrace = backtrace_create(2);
|
||||||
|
enable_thread(before);
|
||||||
|
|
||||||
/* update header of linked list neighbours */
|
/* update header of linked list neighbours */
|
||||||
|
lock->lock(lock);
|
||||||
if (hdr->next)
|
if (hdr->next)
|
||||||
{
|
{
|
||||||
hdr->next->previous = hdr;
|
hdr->next->previous = hdr;
|
||||||
}
|
}
|
||||||
hdr->previous->next = hdr;
|
hdr->previous->next = hdr;
|
||||||
install_hooks();
|
lock->unlock(lock);
|
||||||
pthread_setschedparam(thread_id, oldpolicy, &oldparams);
|
|
||||||
return hdr + 1;
|
return hdr + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(leak_detective_t, destroy, void,
|
METHOD(leak_detective_t, destroy, void,
|
||||||
private_leak_detective_t *this)
|
private_leak_detective_t *this)
|
||||||
{
|
{
|
||||||
if (installed)
|
disable_leak_detective();
|
||||||
{
|
lock->destroy(lock);
|
||||||
uninstall_hooks();
|
thread_disabled->destroy(thread_disabled);
|
||||||
}
|
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,20 +745,12 @@ leak_detective_t *leak_detective_create()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
lock = spinlock_create();
|
||||||
|
thread_disabled = thread_value_create(NULL);
|
||||||
|
|
||||||
if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
|
if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)
|
||||||
{
|
{
|
||||||
cpu_set_t mask;
|
enable_leak_detective();
|
||||||
|
|
||||||
CPU_ZERO(&mask);
|
|
||||||
CPU_SET(0, &mask);
|
|
||||||
|
|
||||||
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "setting CPU affinity failed: %m");
|
|
||||||
}
|
|
||||||
|
|
||||||
install_hooks();
|
|
||||||
}
|
}
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue