@@ -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
new file mode 100644
@@ -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);
+}
new file mode 100755
@@ -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
@@ -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);
}
@@ -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);
}