Hi together,
please find attached patch that adds support for glibc malloc hooks and so
make it possible to debug memory problems in external libraries.
Comments?
--
Thanks,
Alex
Index: gwlib/thread.h
===================================================================
RCS file: /home/cvs/gateway/gwlib/thread.h,v
retrieving revision 1.23
diff -a -u -p -r1.23 thread.h
--- gwlib/thread.h 22 Jan 2004 14:08:25 -0000 1.23
+++ gwlib/thread.h 2 Feb 2005 17:04:02 -0000
@@ -85,6 +85,25 @@ typedef struct {
#endif
} Mutex;
+#ifdef MUTEX_STATS
+#define GW_MUTEX_INITIALIZER \
+{ \
+ .mutex = PTHREAD_MUTEX_INITIALIZER, \
+ .owner = -1, \
+ .dynamic = 0, \
+ .filename = __FILE__, \
+ .lineno = __LINE__, \
+ .locks = 0, \
+ .collisions = 0, \
+}
+#else
+#define GW_MUTEX_INITIALIZER \
+{ \
+ .mutex = PTHREAD_MUTEX_INITIALIZER, \
+ .owner = -1, \
+ .dynamic = 0, \
+}
+#endif
/*
* Create a Mutex.
Index: gwlib/gwmem-check.c
===================================================================
RCS file: /home/cvs/gateway/gwlib/gwmem-check.c,v
retrieving revision 1.27
diff -a -u -p -r1.27 gwmem-check.c
--- gwlib/gwmem-check.c 21 Jan 2005 13:50:46 -0000 1.27
+++ gwlib/gwmem-check.c 2 Feb 2005 17:04:02 -0000
@@ -131,7 +131,7 @@ static int slow = 0;
/* We have to use a static mutex here, because otherwise the mutex_create
* call would try to allocate memory with gw_malloc before we're
* initialized. */
-static Mutex gwmem_lock;
+static Mutex gwmem_lock = GW_MUTEX_INITIALIZER;
struct location
{
@@ -192,6 +192,76 @@ static long highest_total_size;
/* Current sum of allocated areas */
static long total_size;
+
+/* glibc malloc debugging */
+#ifdef __GLIBC__
+#include <malloc.h>
+static void *gw_check_malloc_hook(size_t, const void*);
+static void gw_check_free_hook(void*, const void*);
+static void *gw_check_realloc_hook(void*, size_t, const void*);
+static void switch_to_gw_hook(void);
+static void init_gw_hook(void);
+
+static void *(*old_malloc_hook)(size_t, const void*);
+static void (*old_free_hook)(void*, const void*);
+static void *(*old_realloc_hook)(void*, size_t, const void*);
+
+void (*__malloc_initialize_hook)(void) = init_gw_hook;
+
+static pthread_mutex_t hook_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void init_gw_hook(void)
+{
+ gw_check_init_mem(1);
+ old_malloc_hook = __malloc_hook;
+ __malloc_hook = gw_check_malloc_hook;
+ old_free_hook = __free_hook;
+ __free_hook = gw_check_free_hook;
+ old_realloc_hook = __realloc_hook;
+ __realloc_hook = gw_check_realloc_hook;
+}
+
+static void switch_to_gw_hook(void)
+{
+ old_malloc_hook = __malloc_hook;
+ __malloc_hook = gw_check_malloc_hook;
+ old_free_hook = __free_hook;
+ __free_hook = gw_check_free_hook;
+ old_realloc_hook = __realloc_hook;
+ __realloc_hook = gw_check_realloc_hook;
+ pthread_mutex_unlock(&hook_lock);
+}
+
+static void switch_to_glibc_hook(void)
+{
+ pthread_mutex_lock(&hook_lock);
+ /* restore old hoocks */
+ __malloc_hook = old_malloc_hook;
+ __free_hook = old_free_hook;
+ __realloc_hook = old_realloc_hook;
+}
+
+
+static void *gw_check_malloc_hook(size_t size, const void *caller)
+{
+ return gw_check_malloc(size, "?", 0, "?");
+}
+
+static void gw_check_free_hook(void *p, const void *caller)
+{
+ gw_check_free(p, "?", 0, "?");
+}
+
+static void *gw_check_realloc_hook(void *ptr, size_t size, const void *caller)
+{
+ return gw_check_realloc(ptr, size, "?", 0, "?");
+}
+#else
+#define switch_to_glibc_hook() do{}while(0)
+#define switch_to_gw_hook() do{}while(0)
+#endif /* __GLIBC__ */
+
+
/* Static functions */
static inline void lock(void)
@@ -341,7 +411,10 @@ static void dump_area(struct area *area)
#if HAVE_BACKTRACE
{
size_t i;
- char **strings = backtrace_symbols(area->frames, area->frame_size);
+ char **strings;
+ switch_to_glibc_hook();
+ strings = backtrace_symbols(area->frames, area->frame_size);
+ switch_to_gw_hook();
debug("gwlib.gwmem", 0, "Backtrace of last malloc/realloc:");
for (i = 0; i < area->frame_size; i++) {
if (strings != NULL)
@@ -349,7 +422,9 @@ static void dump_area(struct area *area)
else
debug("gwlib.gwmem", 0, "%p", area->frames[i]);
}
+ switch_to_glibc_hook();
free(strings);
+ switch_to_gw_hook();
}
#endif
}
@@ -415,7 +490,7 @@ static void change_total_size(long chang
}
static struct area *record_allocation(unsigned char *p, size_t size,
- const char *filename, long lineno, const char *function)
+ const char *filename, long lineno, const char *function)
{
struct area *area;
static struct area empty_area;
@@ -433,7 +508,9 @@ static struct area *record_allocation(un
area->allocator.lineno = lineno;
area->allocator.function = function;
#if HAVE_BACKTRACE
+ switch_to_glibc_hook();
area->frame_size = backtrace(area->frames, sizeof(area->frames) / sizeof(void*));
+ switch_to_gw_hook();
#endif
startmark(area->area, num_allocations);
@@ -468,7 +545,9 @@ static void drop_from_free_ring(long ind
error(0, "Freed area %p has been tampered with.", area->area);
dump_area(area);
}
+ switch_to_glibc_hook();
free((unsigned char *)area->area - MARKER_SIZE);
+ switch_to_gw_hook();
}
static void put_on_free_ring(struct area *area)
@@ -499,15 +578,12 @@ static void free_area(struct area *area)
void gw_check_init_mem(int slow_flag)
{
- mutex_init_static(&gwmem_lock);
slow = slow_flag;
initialized = 1;
}
void gw_check_shutdown(void)
{
- mutex_destroy(&gwmem_lock);
- initialized = 0;
}
void *gw_check_malloc(size_t size, const char *filename, long lineno,
@@ -520,7 +596,9 @@ void *gw_check_malloc(size_t size, const
/* ANSI C89 says malloc(0) is implementation-defined. Avoid it. */
gw_assert(size > 0);
+ switch_to_glibc_hook();
p = malloc(size + 2 * MARKER_SIZE);
+ switch_to_gw_hook();
if (p == NULL)
panic(errno, "Memory allocation of %d bytes failed.", size);
p += MARKER_SIZE;
@@ -567,7 +645,9 @@ void *gw_check_realloc(void *p, size_t s
unsigned char *new_p;
new_size = round_pow2(size + 2 * MARKER_SIZE);
+ switch_to_glibc_hook();
new_p = malloc(new_size);
+ switch_to_gw_hook();
new_size -= 2 * MARKER_SIZE;
new_p += MARKER_SIZE;
memcpy(new_p, p, area->area_size);