| #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; |
| } |