From: Stefan Hajnoczi <[email protected]>
The MALLOC_TRACE output didn't look useful when I tried it either.
Instead I used the following to find origin of the leak. Still very basic but
works better with qemu_malloc() and friends.
This is just a hack but I wanted to share it in case someone finds it useful in
the future.
---
Makefile.objs | 2 +-
leakcheck.c | 17 +++++++++++++++
leakcheck.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
osdep.c | 7 +++++-
qemu-malloc.c | 26 +++++++++++++++++++----
5 files changed, 108 insertions(+), 7 deletions(-)
create mode 100644 leakcheck.c
create mode 100755 leakcheck.py
diff --git a/Makefile.objs b/Makefile.objs
index 59ec879..82a4fac 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -7,7 +7,7 @@ qobject-obj-y += qerror.o
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
-block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
+block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
leakcheck.o
block-obj-y += nbd.o block.o aio.o aes.o osdep.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
diff --git a/leakcheck.c b/leakcheck.c
new file mode 100644
index 0000000..a5fa51a
--- /dev/null
+++ b/leakcheck.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+static FILE *fp;
+
+extern void leakcheck_log(char action, void *old_addr, void *addr, size_t
size, void *ret1);
+
+void leakcheck_log(char action, void *old_addr, void *addr, size_t size, void
*ret1)
+{
+ if (!fp) {
+ fp = fopen("/tmp/leakcheck.log", "w");
+ if (!fp) {
+ return;
+ }
+ }
+
+ fprintf(fp, "%c %p %p %zd %p\n", action, old_addr, addr, size, ret1);
+}
diff --git a/leakcheck.py b/leakcheck.py
new file mode 100755
index 0000000..64b1a1b
--- /dev/null
+++ b/leakcheck.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+import sys
+
+class Event(object):
+ def __init__(self, num, action, old_addr, addr, size, ret_addr):
+ self.num = num
+ self.action = action
+ self.old_addr = old_addr
+ self.addr = addr
+ self.size = size
+ self.ret_addr = ret_addr
+
+ def __str__(self):
+ return '%d %s %s %s %s %s' % (self.num, self.action, self.old_addr,
self.addr, self.size, self.ret_addr)
+
+def malloc(event):
+ if event.addr in allocs:
+ sys.stderr.write('malloc returned duplicate address from %s\n' % event)
+ allocs[event.addr] = event
+
+def free(event):
+ if event.addr == '(nil)':
+ return
+ if event.addr not in allocs:
+ sys.stderr.write('free of unallocated address from %s\n' % event)
+ return
+ malloc_event = allocs[event.addr]
+ del allocs[event.addr]
+ if (malloc_event.action in 'msz' and event.action == 'f') or \
+ (malloc_event.action == 'a' and event.action == 'v'):
+ return
+ sys.stderr.write('mismatched actions for %s and %s\n' % (malloc_event,
event))
+
+def realloc(event):
+ free(Event(event.num, 'f', event.old_addr, '(nil)', 0, event.ret_addr))
+ malloc(Event(event.num, 'm', '(nil)', event.addr, event.size,
event.ret_addr))
+
+allocs = {}
+watermark = 0
+event_num = 0
+for line in sys.stdin:
+ event_num += 1
+
+ cmd = line.strip()
+ if cmd == 'watermark':
+ watermark = event_num
+ continue
+
+ action, old_addr, addr, size, ret_addr = cmd.split()
+ event = Event(event_num, action, old_addr, addr, size, ret_addr)
+ if action in 'amsz':
+ malloc(event)
+ elif action in 'fv':
+ free(event)
+ elif action == 'r':
+ realloc(event)
+ else:
+ sys.stderr.write('invalid action "%c"\n' % action)
+ sys.exit(1)
+
+for event in sorted(allocs.itervalues(), key=lambda e: e.num):
+ if event.num > watermark:
+ print event
diff --git a/osdep.c b/osdep.c
index 8a710e7..40788e5 100644
--- a/osdep.c
+++ b/osdep.c
@@ -95,6 +95,8 @@ void qemu_vfree(void *ptr)
#else
+extern void leakcheck_log(char action, void *old_addr, void *addr, size_t
size, void *ret1);
+
void *qemu_memalign(size_t alignment, size_t size)
{
#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
@@ -110,7 +112,9 @@ void *qemu_memalign(size_t alignment, size_t size)
#elif defined(CONFIG_BSD)
return oom_check(valloc(size));
#else
- return oom_check(memalign(alignment, size));
+ void *p = oom_check(memalign(alignment, size));
+ leakcheck_log('a', NULL, p, size, __builtin_return_address(0));
+ return p;
#endif
}
@@ -126,6 +130,7 @@ void *qemu_vmalloc(size_t size)
void qemu_vfree(void *ptr)
{
+ leakcheck_log('v', NULL, ptr, 0, __builtin_return_address(0));
free(ptr);
}
diff --git a/qemu-malloc.c b/qemu-malloc.c
index 6cdc5de..bf832f2 100644
--- a/qemu-malloc.c
+++ b/qemu-malloc.c
@@ -24,6 +24,8 @@
#include "qemu-common.h"
#include <stdlib.h>
+extern void leakcheck_log(char action, void *old_addr, void *addr, size_t
size, void *ret1);
+
static void *oom_check(void *ptr)
{
if (ptr == NULL) {
@@ -39,6 +41,7 @@ void *get_mmap_addr(unsigned long size)
void qemu_free(void *ptr)
{
+ leakcheck_log('f', NULL, ptr, 0, __builtin_return_address(0));
free(ptr);
}
@@ -51,7 +54,7 @@ static int allow_zero_malloc(void)
#endif
}
-void *qemu_malloc(size_t size)
+static void *qemu_malloc_common(size_t size)
{
if (!size && !allow_zero_malloc()) {
abort();
@@ -59,19 +62,30 @@ void *qemu_malloc(size_t size)
return oom_check(malloc(size ? size : 1));
}
+void *qemu_malloc(size_t size)
+{
+ void *p = qemu_malloc_common(size);
+ leakcheck_log('m', NULL, p, size, __builtin_return_address(0));
+ return p;
+}
+
void *qemu_realloc(void *ptr, size_t size)
{
if (!size && !allow_zero_malloc()) {
abort();
}
- return oom_check(realloc(ptr, size ? size : 1));
+ size = size ? size : 1;
+ void *p = oom_check(realloc(ptr, size));
+ leakcheck_log('r', ptr, p, size, __builtin_return_address(0));
+ return p;
}
void *qemu_mallocz(size_t size)
{
void *ptr;
- ptr = qemu_malloc(size);
+ ptr = qemu_malloc_common(size);
memset(ptr, 0, size);
+ leakcheck_log('z', NULL, ptr, size, __builtin_return_address(0));
return ptr;
}
@@ -79,8 +93,9 @@ char *qemu_strdup(const char *str)
{
char *ptr;
size_t len = strlen(str);
- ptr = qemu_malloc(len + 1);
+ ptr = qemu_malloc_common(len + 1);
memcpy(ptr, str, len + 1);
+ leakcheck_log('s', NULL, ptr, len + 1, __builtin_return_address(0));
return ptr;
}
@@ -93,8 +108,9 @@ char *qemu_strndup(const char *str, size_t size)
size = end - str;
}
- new = qemu_malloc(size + 1);
+ new = qemu_malloc_common(size + 1);
new[size] = 0;
+ leakcheck_log('s', NULL, new, size + 1, __builtin_return_address(0));
return memcpy(new, str, size);
}
--
1.7.0
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html