diff options
-rw-r--r-- | src/lib9/debugmalloc.c | 166 | ||||
-rw-r--r-- | src/lib9/malloc.c | 43 |
2 files changed, 179 insertions, 30 deletions
diff --git a/src/lib9/debugmalloc.c b/src/lib9/debugmalloc.c new file mode 100644 index 00000000..3958e243 --- /dev/null +++ b/src/lib9/debugmalloc.c @@ -0,0 +1,166 @@ +#include <u.h> +#define NOPLAN9DEFINES +#include <libc.h> + +/* + * The Unix libc routines cannot be trusted to do their own locking. + * Sad but apparently true. + */ +static Lock malloclock; +static int mallocpid; + +/* + * The Unix mallocs don't do nearly enough error checking + * for my tastes. We'll waste another 24 bytes per guy so that + * we can. This is severely antisocial, since now free and p9free + * are not interchangeable. + */ +int debugmalloc; + +#define Overhead (debugmalloc ? (6*sizeof(ulong)) : 0) +#define MallocMagic 0xA110C09 +#define ReallocMagic 0xB110C09 +#define CallocMagic 0xC110C09 +#define FreeMagic 0xF533F533 +#define CheckMagic 0 +#define END "\x7F\x2E\x55\x23" + +static void +whoops(void *v) +{ + fprint(2, "bad malloc block %p\n", v); + abort(); +} + +static void* +mark(void *v, ulong pc, ulong n, ulong magic) +{ + ulong *u; + char *p; + + if(!debugmalloc) + return v; + + if(v == nil) + return nil; + + if(magic == FreeMagic || magic == CheckMagic){ + u = (ulong*)((char*)v-4*sizeof(ulong)); + if(u[0] != MallocMagic && u[0] != ReallocMagic && u[0] != CallocMagic) + whoops(v); + n = u[1]; + p = (char*)v+n; + if(memcmp(p, END, 4) != 0) + whoops(v); + if(magic != CheckMagic){ + u[0] = FreeMagic; + u[1] = u[2] = u[3] = pc; + if(n > 16){ + u[4] = u[5] = u[6] = u[7] = pc; + memset((char*)v+16, 0xFB, n-16); + } + } + return u; + }else{ + u = v; + u[0] = magic; + u[1] = n; + u[2] = 0; + u[3] = 0; + if(magic == ReallocMagic) + u[3] = pc; + else + u[2] = pc; + p = (char*)(u+4)+n; + memmove(p, END, 4); + return u+4; + } +} + +void +setmalloctag(void *v, ulong t) +{ + ulong *u; + + if(!debugmalloc) + return; + + if(v == nil) + return; + u = mark(v, 0, 0, 0); + u[2] = t; +} + +void +setrealloctag(void *v, ulong t) +{ + ulong *u; + + if(!debugmalloc) + return; + + if(v == nil) + return; + u = mark(v, 0, 0, 0); + u[3] = t; +} + +void* +p9malloc(ulong n) +{ + void *v; + if(n == 0) + n++; +//fprint(2, "%s %d malloc\n", argv0, getpid()); + lock(&malloclock); + mallocpid = getpid(); + v = malloc(n+Overhead); + v = mark(v, getcallerpc(&n), n, MallocMagic); + unlock(&malloclock); +//fprint(2, "%s %d donemalloc\n", argv0, getpid()); + return v; +} + +void +p9free(void *v) +{ + if(v == nil) + return; + +//fprint(2, "%s %d free\n", argv0, getpid()); + lock(&malloclock); + mallocpid = getpid(); + v = mark(v, getcallerpc(&v), 0, FreeMagic); + free(v); + unlock(&malloclock); +//fprint(2, "%s %d donefree\n", argv0, getpid()); +} + +void* +p9calloc(ulong a, ulong b) +{ + void *v; + +//fprint(2, "%s %d calloc\n", argv0, getpid()); + lock(&malloclock); + mallocpid = getpid(); + v = calloc(a*b+Overhead, 1); + v = mark(v, getcallerpc(&a), a*b, CallocMagic); + unlock(&malloclock); +//fprint(2, "%s %d donecalloc\n", argv0, getpid()); + return v; +} + +void* +p9realloc(void *v, ulong n) +{ +//fprint(2, "%s %d realloc\n", argv0, getpid()); + lock(&malloclock); + mallocpid = getpid(); + v = mark(v, getcallerpc(&v), 0, CheckMagic); + v = realloc(v, n+Overhead); + v = mark(v, getcallerpc(&v), n, ReallocMagic); + unlock(&malloclock); +//fprint(2, "%s %d donerealloc\n", argv0, getpid()); + return v; +} diff --git a/src/lib9/malloc.c b/src/lib9/malloc.c index 7c5b1786..2c6731ea 100644 --- a/src/lib9/malloc.c +++ b/src/lib9/malloc.c @@ -1,58 +1,41 @@ -#include <u.h> -#define NOPLAN9DEFINES -#include <libc.h> - /* - * The Unix libc routines cannot be trusted to do their own locking. - * Sad but apparently true. + * These are here mainly so that I can link against + * debugmalloc.c instead and not recompile the world. */ -static Lock malloclock; +#include <u.h> +#define NOPLAN9DEFINES +#include <libc.h> void* p9malloc(ulong n) { void *v; + if(n == 0) n++; -//fprint(2, "%s %d malloc\n", argv0, getpid()); - lock(&malloclock); - v = malloc(n); - unlock(&malloclock); -//fprint(2, "%s %d donemalloc\n", argv0, getpid()); - return v; + return malloc(n); } void p9free(void *v) { -//fprint(2, "%s %d free\n", argv0, getpid()); - lock(&malloclock); + if(v == nil) + return; free(v); - unlock(&malloclock); -//fprint(2, "%s %d donefree\n", argv0, getpid()); } void* p9calloc(ulong a, ulong b) { - void *v; + if(a*b == 0) + a = b = 1; -//fprint(2, "%s %d calloc\n", argv0, getpid()); - lock(&malloclock); - v = calloc(a, b); - unlock(&malloclock); -//fprint(2, "%s %d donecalloc\n", argv0, getpid()); - return v; + return calloc(a*b, 1); } void* p9realloc(void *v, ulong n) { -//fprint(2, "%s %d realloc\n", argv0, getpid()); - lock(&malloclock); - v = realloc(v, n); - unlock(&malloclock); -//fprint(2, "%s %d donerealloc\n", argv0, getpid()); - return v; + return realloc(v, n); } |