Skip to content

Instantly share code, notes, and snippets.

@swarren
Last active September 5, 2015 04:50
Show Gist options
  • Save swarren/ae40611b9c5493470a01 to your computer and use it in GitHub Desktop.
Save swarren/ae40611b9c5493470a01 to your computer and use it in GitHub Desktop.
Malloc leak tracing hacks for U-Boot
From 3cb19cec2bbe7d5f4dc05eec393ccf48189a3d9a Mon Sep 17 00:00:00 2001
From: Stephen Warren <swarren@nvidia.com>
Date: Fri, 4 Sep 2015 11:29:23 -0600
Subject: [PATCH 1/2] dump malloc_stats()
X-NVConfidentiality: public
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
common/cmd_dfu.c | 2 ++
common/cmd_fs.c | 5 ++++-
common/dlmalloc.c | 2 +-
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/common/cmd_dfu.c b/common/cmd_dfu.c
index 857148f8afef..82b70be71632 100644
--- a/common/cmd_dfu.c
+++ b/common/cmd_dfu.c
@@ -9,6 +9,7 @@
*/
#include <common.h>
+#include <malloc.h>
#include <watchdog.h>
#include <dfu.h>
#include <g_dnl.h>
@@ -78,6 +79,7 @@ done:
run_command("reset", 0);
g_dnl_clear_detach();
+malloc_stats();
return ret;
}
diff --git a/common/cmd_fs.c b/common/cmd_fs.c
index e146254f6d68..1ed0312ca04a 100644
--- a/common/cmd_fs.c
+++ b/common/cmd_fs.c
@@ -19,6 +19,7 @@
#include <common.h>
#include <command.h>
#include <fs.h>
+#include <malloc.h>
static int do_size_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
@@ -54,7 +55,9 @@ U_BOOT_CMD(
static int do_save_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
- return do_save(cmdtp, flag, argc, argv, FS_TYPE_ANY);
+ int ret = do_save(cmdtp, flag, argc, argv, FS_TYPE_ANY);
+malloc_stats();
+return ret;
}
U_BOOT_CMD(
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index b5bb05191c24..845c0b4ce24b 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -1,6 +1,6 @@
#include <common.h>
-#ifdef CONFIG_SANDBOX
+#if 1//def CONFIG_SANDBOX
#define DEBUG
#endif
--
1.9.1
From 23a5881984e5f52cf475998219e6e05b33b121f5 Mon Sep 17 00:00:00 2001
From: Stephen Warren <swarren@nvidia.com>
Date: Thu, 3 Sep 2015 22:11:16 -0600
Subject: [PATCH 2/2] malloc debug
X-NVConfidentiality: public
Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
common/cli_hush.c | 26 ++++++++++++++++
common/dlmalloc.c | 89 ++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 94 insertions(+), 21 deletions(-)
diff --git a/common/cli_hush.c b/common/cli_hush.c
index 296542f4c2d6..a333dcb42862 100644
--- a/common/cli_hush.c
+++ b/common/cli_hush.c
@@ -386,9 +386,33 @@ static void __syntax(char *file, int line) {
#endif
#ifdef __U_BOOT__
+#if 0
static void *xmalloc(size_t size);
static void *xrealloc(void *ptr, size_t size);
#else
+static inline void *xmalloc(size_t size)
+{
+ void *p = NULL;
+
+ if (!(p = malloc(size))) {
+ printf("ERROR : memory not allocated\n");
+ for(;;);
+ }
+ return p;
+}
+
+static inline void *xrealloc(void *ptr, size_t size)
+{
+ void *p = NULL;
+
+ if (!(p = realloc(ptr, size))) {
+ printf("ERROR : memory not allocated\n");
+ for(;;);
+ }
+ return p;
+}
+#endif
+#else
/* Index of subroutines: */
/* function prototypes for builtins */
static int builtin_cd(struct child_prog *child);
@@ -3304,6 +3328,7 @@ int u_boot_hush_start(void)
return 0;
}
+#if 0
static void *xmalloc(size_t size)
{
void *p = NULL;
@@ -3325,6 +3350,7 @@ static void *xrealloc(void *ptr, size_t size)
}
return p;
}
+#endif
#endif /* __U_BOOT__ */
#ifndef __U_BOOT__
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index 845c0b4ce24b..5ae2a5900e01 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -948,6 +948,12 @@ void malloc_stats();
DECLARE_GLOBAL_DATA_PTR;
+#if __STD_C
+void free_imp(Void_t* mem);
+#else
+void free_imp(mem) Void_t* mem;
+#endif
+
/*
Emulation of sbrk for WIN32
All code within the ifdef WIN32 is untested by me.
@@ -2084,7 +2090,7 @@ static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
SIZE_SZ|PREV_INUSE;
/* If possible, release the rest. */
if (old_top_size >= MINSIZE)
- fREe(chunk2mem(old_top));
+ free_imp(chunk2mem(old_top));
}
}
@@ -2163,9 +2169,9 @@ static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
*/
#if __STD_C
-Void_t* mALLOc(size_t bytes)
+Void_t* malloc_imp(size_t bytes)
#else
-Void_t* mALLOc(bytes) size_t bytes;
+Void_t* malloc_imp(bytes) size_t bytes;
#endif
{
mchunkptr victim; /* inspected/selected chunk */
@@ -2409,6 +2415,17 @@ Void_t* mALLOc(bytes) size_t bytes;
}
+#if __STD_C
+Void_t* mALLOc(size_t bytes)
+#else
+Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ Void_t *p = malloc_imp(bytes);
+printf("malloc(%ld) -> %p @%p\n", bytes, p, __builtin_return_address(0));
+ return p;
+}
+
@@ -2435,9 +2452,9 @@ Void_t* mALLOc(bytes) size_t bytes;
#if __STD_C
-void fREe(Void_t* mem)
+void free_imp(Void_t* mem)
#else
-void fREe(mem) Void_t* mem;
+void free_imp(mem) Void_t* mem;
#endif
{
mchunkptr p; /* chunk corresponding to mem */
@@ -2532,7 +2549,15 @@ void fREe(mem) Void_t* mem;
frontlink(p, sz, idx, bck, fwd);
}
-
+#if __STD_C
+void fREe(Void_t* mem)
+#else
+void fREe(mem) Void_t* mem;
+#endif
+{
+printf("free(%p) @%p\n", mem, __builtin_return_address(0));
+ free_imp(mem);
+}
@@ -2573,9 +2598,9 @@ void fREe(mem) Void_t* mem;
#if __STD_C
-Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+Void_t* realloc_imp(Void_t* oldmem, size_t bytes)
#else
-Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+Void_t* realloc_imp(oldmem, bytes) Void_t* oldmem; size_t bytes;
#endif
{
INTERNAL_SIZE_T nb; /* padded request size */
@@ -2600,13 +2625,13 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
mchunkptr fwd; /* misc temp for linking */
#ifdef REALLOC_ZERO_BYTES_FREES
- if (bytes == 0) { fREe(oldmem); return 0; }
+ if (bytes == 0) { free_imp(oldmem); return 0; }
#endif
if ((long)bytes < 0) return NULL;
/* realloc of null is supposed to be same as malloc */
- if (oldmem == NULL) return mALLOc(bytes);
+ if (oldmem == NULL) return malloc_imp(bytes);
#ifdef CONFIG_SYS_MALLOC_F_LEN
if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
@@ -2631,7 +2656,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* Note the extra SIZE_SZ overhead. */
if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
/* Must alloc, copy, free. */
- newmem = mALLOc(bytes);
+ newmem = malloc_imp(bytes);
if (newmem == 0) return 0; /* propagate failure */
MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
@@ -2733,7 +2758,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* Must allocate */
- newmem = mALLOc (bytes);
+ newmem = malloc_imp(bytes);
if (newmem == NULL) /* propagate failure */
return NULL;
@@ -2750,7 +2775,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* Otherwise copy, free, and exit */
MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
- fREe(oldmem);
+ free_imp(oldmem);
return newmem;
}
@@ -2764,7 +2789,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
set_head_size(newp, nb);
set_head(remainder, remainder_size | PREV_INUSE);
set_inuse_bit_at_offset(remainder, remainder_size);
- fREe(chunk2mem(remainder)); /* let free() deal with it */
+ free_imp(chunk2mem(remainder)); /* let free() deal with it */
}
else
{
@@ -2776,6 +2801,17 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
return chunk2mem(newp);
}
+#if __STD_C
+Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ Void_t *p = realloc_imp(oldmem, bytes);
+printf("realloc(%p, %ld) -> %p @%p\n", oldmem, bytes, p, __builtin_return_address(0));
+ return p;
+}
+
@@ -2799,9 +2835,9 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
#if __STD_C
-Void_t* mEMALIGn(size_t alignment, size_t bytes)
+Void_t* memalign_imp(size_t alignment, size_t bytes)
#else
-Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+Void_t* memalign_imp(alignment, bytes) size_t alignment; size_t bytes;
#endif
{
INTERNAL_SIZE_T nb; /* padded request size */
@@ -2818,7 +2854,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
/* If need less alignment than we give anyway, just relay to malloc */
- if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+ if (alignment <= MALLOC_ALIGNMENT) return malloc_imp(bytes);
/* Otherwise, ensure that it is at least a minimum chunk size */
@@ -2827,7 +2863,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
/* Call malloc with worst case padding to hit alignment. */
nb = request2size(bytes);
- m = (char*)(mALLOc(nb + alignment + MINSIZE));
+ m = (char*)(malloc_imp(nb + alignment + MINSIZE));
if (m == NULL) return NULL; /* propagate failure */
@@ -2872,7 +2908,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
set_head(newp, newsize | PREV_INUSE);
set_inuse_bit_at_offset(newp, newsize);
set_head_size(p, leadsize);
- fREe(chunk2mem(p));
+ free_imp(chunk2mem(p));
p = newp;
assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
@@ -2887,7 +2923,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
remainder = chunk_at_offset(p, nb);
set_head(remainder, remainder_size | PREV_INUSE);
set_head_size(p, nb);
- fREe(chunk2mem(remainder));
+ free_imp(chunk2mem(remainder));
}
check_inuse_chunk(p);
@@ -2895,6 +2931,16 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
}
+#if __STD_C
+Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ Void_t *p = memalign_imp(alignment, bytes);
+printf("memalign(%ld, %ld) -> %p @%p\n", alignment, bytes, p, __builtin_return_address(0));
+ return p;
+}
@@ -2954,7 +3000,7 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
INTERNAL_SIZE_T oldtopsize = chunksize(top);
#endif
#endif
- Void_t* mem = mALLOc (sz);
+ Void_t* mem = malloc_imp (sz);
if ((long)n < 0) return NULL;
@@ -2990,6 +3036,7 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
#endif
MALLOC_ZERO(mem, csz - SIZE_SZ);
+printf("calloc(%ld, %ld) -> %p @%p\n", n, elem_size, mem, __builtin_return_address(0));
return mem;
}
}
--
1.9.1
#!/usr/bin/python3
import re
import sys
re_alloc = re.compile('[mc]alloc\(([\d, ]+)\) -> ([A-Za-z0-9]+) @([A-Za-z0-9]+)')
re_memalign = re.compile('memalign\(\d+, (\d+)\) -> ([A-Za-z0-9]+) @([A-Za-z0-9]+)')
re_realloc = re.compile('realloc\(([A-Za-z0-9]+), ([\d, ]+)\) -> ([A-Za-z0-9]+) @([A-Za-z0-9]+)')
re_free = re.compile('free\(([A-Za-z0-9]+)\) @([A-Za-z0-9]+)')
re_relocoff = re.compile('reloc off = (0x[A-Za-z0-9]+)')
MALLOC = 0
REALLOC = 1
FREE = 2
entries = []
relocoff = 0
lnum = 0
for l in sys.stdin.readlines():
lnum += 1
m = re_alloc.match(l)
if m:
entries.append({
'lnum': lnum,
'type': MALLOC,
'size': m.group(1),
'ptr': m.group(2),
'caller': m.group(3)
})
continue
m = re_memalign.match(l)
if m:
entries.append({
'lnum': lnum,
'type': MALLOC,
'size': m.group(1),
'ptr': m.group(2),
'caller': m.group(3)
})
continue
m = re_realloc.match(l)
if m:
entries.append({
'lnum': lnum,
'type': REALLOC,
'oldptr': m.group(1),
'size': m.group(2),
'ptr': m.group(3),
'caller': m.group(4),
})
continue
m = re_free.match(l)
if m:
entries.append({
'lnum': lnum,
'type': FREE,
'oldptr': m.group(1),
'caller': m.group(2)
})
continue
m = re_relocoff.match(l)
if m:
relocoff = int(m.group(1), 16)
continue
print("No format match: " + l.strip())
num_entries = len(entries)
for i in range(num_entries):
if entries[i]['type'] == FREE:
continue
ptr = entries[i]['ptr']
found = False
for j in range(i + 1, num_entries):
if entries[j]['type'] == MALLOC:
continue
if entries[j]['oldptr'] == ptr:
found = True
break
if not found:
caller = int(entries[i]['caller'], 16) - relocoff
print('No match: line', str(entries[i]['lnum']), 'caller %x' % caller, 'size', entries[i]['size'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment