#include "config.h" #ifdef USE_MALLOC #include "externs.h" #include <signal.h> #include <stdarg.h> /* #define MALTRACE */ #define USE_MAGIC /**/ #define RECORD_CALLER /**/ #define DO_FILLS /**/ /* #define RECORD_BUSY */ #define ALIGNMENT 4 #define PANIC_POOL 65536 #define OFFSET ((((sizeof(int)-1)/ALIGNMENT)+1)*ALIGNMENT) #ifdef NeXT #define malloc bsd_malloc #define realloc bsd_realloc #define free bsd_free #endif #undef malloc #undef realloc #undef calloc #undef free extern void *malloc(int); extern void *realloc(const void *,int); extern void free(const void *); static char panic_pool[PANIC_POOL]; static int panicked = 0; static int used = 0; void setpanicmalloc(void) { panicked = 1; } static void chkused(void) { if (used > PANIC_POOL) { write(2,"out of panic memory\n",20); abort(); } } static void *panic_malloc(int nb) { if (! panicked) return(malloc(nb)); if (nb == 0) return(0); nb = (((nb-1)/ALIGNMENT)+1)*ALIGNMENT; used += nb + OFFSET; chkused(); *((int *)&panic_pool[used-nb-OFFSET]) = nb; return(&panic_pool[used-nb]); } static void *panic_realloc(void *old, int newnb) { int oldnb; if (! panicked) return(realloc(old,newnb)); if (old == 0) return(panic_malloc(newnb)); if (((char *)old < &panic_pool[0]) || ((char *)old >= &panic_pool[PANIC_POOL])) { write(2,"bad panic realloc\n",18); abort(); } oldnb = *(int *)(((char *)old)-OFFSET); newnb = (((newnb-1)/ALIGNMENT)+1)*ALIGNMENT; if (((char *)old)+oldnb == &panic_pool[used]) { used += newnb - oldnb; chkused(); *(int *)(((char *)old)-OFFSET) = newnb; return(old); } else { void *new; new = panic_malloc(newnb); bcopy(old,new,(oldnb<newnb)?oldnb:newnb); return(new); } } static void panic_free(void *obj) { if (! panicked) { free(obj); return; } } #undef malloc #undef realloc #undef free #define malloc(nb) panic_malloc(nb) #define realloc(old,nb) panic_realloc(old,nb) #define free(old) panic_free(old) #if defined(MALTRACE) || defined(RECORD_BUSY) char *fmt_aux(char *bp,unsigned int n,int b) { if (n < b) { *bp++ = "0123456789abcdef"[n]; } else { bp = fmt_aux(bp,n/b,b); bp = fmt_aux(bp,n%b,b); } *bp = '\0'; return(bp); } #endif #if defined(MALTRACE) || defined(RECORD_BUSY) #define fmt_dec(bp,i) (void)fmt_aux(bp,i,10) #define fmt_hex(bp,i) (void)fmt_aux(bp,i,16) #endif #ifdef USE_MAGIC #define MMAGIC 0xdeadbeefU #endif #ifdef RECORD_BUSY static unsigned long int busy[BUSY_SIZE]; static int busy_fill = 0; #endif #ifdef RECORD_BUSY static void record_busy(unsigned long int p) { char buf[128]; register int l; register int m; register int h; register unsigned long int v; l = -1; h = busy_fill; if (h >= BUSY_SIZE) { strcpy(&buf[0],"malloc busy table overflow!\n"); write(2,&buf[0],strlen(&buf[0])); abort(); } while (h-l > 1) { m = (h + l) / 2; v = busy[m]; if (v <= p) l = m; if (v >= p) h = m; } if (l == h) { strcpy(&buf[0],"malloc returned 0x"); fmt_hex(&buf[strlen(&buf[0])],(int)p); strcpy(&buf[strlen(&buf[0])],"twice!\n"); write(2,&buf[0],strlen(&buf[0])); abort(); } if (h < busy_fill) { bcopy((char *)&busy[h],(char *)&busy[h+1],(busy_fill-h)*sizeof(busy[0])); } busy[h] = p; busy_fill ++; } #endif #ifdef RECORD_BUSY static void record_unbusy(unsigned long int p) { char buf[128]; register int l; register int m; register int h; register unsigned long int v; l = -1; h = busy_fill; if (h < 1) { strcpy(&buf[0],"malloc busy table underflow!\n"); write(2,&buf[0],strlen(&buf[0])); abort(); } while (h-l > 1) { m = (h + l) / 2; v = busy[m]; if (v <= p) l = m; if (v >= p) h = m; } if (l != h) { strcpy(&buf[0],"freeing unallocated 0x"); fmt_hex(&buf[strlen(&buf[0])],(int)p); strcpy(&buf[strlen(&buf[0])],"!\n"); write(2,&buf[0],strlen(&buf[0])); abort(); } busy_fill --; if (h < busy_fill) { bcopy((char *)&busy[h+1],(char *)&busy[h],(busy_fill-h)*sizeof(busy[0])); } } #endif #ifdef DO_FILLS static void fill(char *p, int n, int i) { unsigned int l; i = '@' + ((i-1) << 3); l = n; for (;n>0;n--) { *p++ = i + (l & 7); l >>= 3; } p[-1] |= 040; } #endif #define XOFF0 0 #if defined(RECORD_CALLER) || defined(DO_FILLS) #define BLK_NB(p) (*(int *)((p)+(XOFF0*ALIGNMENT))) #define XOFF1 (XOFF0+1) #else #define XOFF1 (XOFF0) #endif #ifdef RECORD_CALLER #define BLK_FL(p) (*(void **) ((p)+((XOFF1 )*ALIGNMENT))) #define BLK_BL(p) (*(void **) ((p)+((XOFF1+1)*ALIGNMENT))) #define BLK_FN(p) (*(const char **) ((p)+((XOFF1+2)*ALIGNMENT))) #define BLK_LN(p) (*(int *) ((p)+((XOFF1+3)*ALIGNMENT))) #define BLK_TM(p) (*(int *) ((p)+((XOFF1+4)*ALIGNMENT))) #define XOFF2 (XOFF1+5) static char *malloc_root = 0; #else #define XOFF2 (XOFF1) #endif #ifdef USE_MAGIC #define BLK_MG(p) (*(unsigned long int *)((p)+(XOFF2*ALIGNMENT))) #define XOFF3 (XOFF2+1) #else #define XOFF3 (XOFF2) #endif #define EXTRABYTES (XOFF3*ALIGNMENT) void *muck_malloc(int nb, const char *file, int line) { char *p; #ifdef MALTRACE char buf[128]; #endif #ifdef MALTRACE strcpy(&buf[0],"[malloc "); fmt_dec(&buf[strlen(&buf[0])],nb); strcpy(&buf[strlen(&buf[0])]," -> "); #endif p = malloc(nb+EXTRABYTES); #ifdef RECORD_BUSY record_busy((unsigned long int)p); #endif #ifdef BLK_NB BLK_NB(p) = nb; #endif #ifdef BLK_FL BLK_FL(p) = malloc_root; BLK_BL(p) = 0; if (malloc_root) BLK_BL(malloc_root) = p; malloc_root = p; #endif #ifdef BLK_FN BLK_FN(p) = file; #endif #ifdef BLK_LN BLK_LN(p) = line; #endif #ifdef BLK_TM BLK_TM(p) = time(0); #endif #ifdef BLK_MG BLK_MG(p) = MMAGIC; #endif p += EXTRABYTES; #ifdef DO_FILLS fill(p,nb,1); #endif #ifdef MALTRACE fmt_hex(&buf[strlen(&buf[0])],(int)p); strcpy(&buf[strlen(&buf[0])],"]\n"); write(2,&buf[0],strlen(&buf[0])); #endif return(p); } void *muck_realloc(void *old, int nb, const char *file, int line) { #ifdef BLK_NB int onb; #endif char *p; #ifdef MALTRACE char buf[128]; #endif #ifdef MALTRACE strcpy(&buf[0],"[realloc "); fmt_hex(&buf[strlen(&buf[0])],(int)old); strcpy(&buf[strlen(&buf[0])],","); fmt_dec(&buf[strlen(&buf[0])],nb); strcpy(&buf[strlen(&buf[0])]," -> "); #endif if (old == 0) { p = malloc(nb+EXTRABYTES); #ifdef RECORD_BUSY record_busy((unsigned long int)p); #endif #ifdef BLK_FL BLK_FL(p) = malloc_root; BLK_BL(p) = 0; if (malloc_root) BLK_BL(malloc_root) = p; malloc_root = p; #endif #ifdef DO_FILLS fill(p+EXTRABYTES,nb,2); #endif } else { p = ((char *)old) - EXTRABYTES; #ifdef BLK_MG if (BLK_MG(p) != MMAGIC) { write(2,"realloc: bad magic number\n",26); abort(); } #endif #ifdef BLK_NB onb = BLK_NB(p); #endif p = realloc(p,nb+EXTRABYTES); #ifdef RECORD_BUSY if (p != ((char *)old)-EXTRABYTES) { record_unbusy((unsigned long int)(((char *)old)-EXTRABYTES)); record_busy((unsigned long int)p); } #endif #ifdef DO_FILLS if (onb < nb) fill(onb+p+EXTRABYTES,nb-onb,3); #endif } #ifdef BLK_NB BLK_NB(p) = nb; #endif #ifdef BLK_FN BLK_FN(p) = file; #endif #ifdef BLK_LN BLK_LN(p) = line; #endif #ifdef BLK_TM BLK_TM(p) = time(0); #endif #ifdef BLK_MG BLK_MG(p) = MMAGIC; #endif p += EXTRABYTES; #ifdef MALTRACE fmt_hex(&buf[strlen(&buf[0])],(int)p); strcpy(&buf[strlen(&buf[0])],"]\n"); write(2,&buf[0],strlen(&buf[0])); #endif return(p); } void *muck_calloc(int siz, int n, const char *file, int line) { write(2,"[calloc]\n",9); abort(); return(0); } void *free_break = 0; /* for debugger patching */ void muck_free(void *obj, const char *file, int line) { char *p; #ifdef MALTRACE char buf[128]; #endif #ifdef MALTRACE strcpy(&buf[0],"[free "); fmt_hex(&buf[strlen(&buf[0])],(int)obj); strcpy(&buf[strlen(&buf[0])],"]\n"); write(2,&buf[0],strlen(&buf[0])); #endif if (obj == 0) return; if (obj == free_break) kill(getpid(),SIGINT); p = ((char *)obj) - EXTRABYTES; #ifdef BLK_MG if (BLK_MG(p) != MMAGIC) { write(2,"free: bad magic number\n",23); abort(); } #endif #ifdef BLK_FL { char *f; char *b; f = BLK_FL(p); b = BLK_BL(p); if (f) BLK_BL(f) = b; if (b) BLK_FL(b) = f; if (! b) malloc_root = f; } #endif #ifdef DO_FILLS fill(p,BLK_NB(p)+EXTRABYTES,4); #endif #ifdef RECORD_BUSY record_unbusy((unsigned long int)p); #endif free(p); } static void cfree_(int i, ...) { va_list ap; void *old; const char *file; int line; va_start(ap,i); old = va_arg(ap,void *); file = va_arg(ap,const char *); line = va_arg(ap,int); muck_free(old,file,line); va_end(ap); } void muck_cfree(const void *obj, const char *file, int line) { cfree_(0,obj,file,line); } #ifdef RECORD_CALLER static void mlcprintf(const char *fmt, ...) { static FILE *mlcfile = 0; va_list ap; if (! mlcfile) { mlcfile = fopen("mlcfile","w"); if (mlcfile == 0) return; } va_start(ap,fmt); vfprintf(mlcfile,fmt,ap); va_end(ap); } #endif #ifdef RECORD_CALLER static void printbytes(char *bytes, int nb) { int i; int c; int nbin; const char *trailer; if (nb > 25) { nb = 25; trailer = " ..."; } else { trailer = ""; } nbin = 0; for (i=0;i<nb;i++) { c = ((unsigned char *)bytes)[i]; if ( (c > 126) || ( (c < 32) && (c != '\t') && (c != '\n') && (c != '\r') ) ) nbin ++; } if ((nbin > 1) || ((nbin == 1) && (bytes[nb-1] != '\0'))) { for (i=0;i<nb;i++) { mlcprintf(" %02x",((unsigned char *)bytes)[i]); } } else { mlcprintf(" "); for (i=0;i<nb;i++) { c = ((unsigned char *)bytes)[i]; switch (c) { case '\0': mlcprintf("\\0"); break; case '\r': mlcprintf("\\r"); break; case '\t': mlcprintf("\\t"); break; case '\n': mlcprintf("\\n"); break; default: mlcprintf("%c",c); } } } mlcprintf("%s\n",trailer); } #endif void malloc_leakcheck(void) { #ifdef RECORD_CALLER char *p; char *p2; int flip; p = malloc_root; p2 = malloc_root; flip = 0; while (p) { mlcprintf("\"%s\", line %d: %d byte%s at %.24s\n", BLK_FN(p), BLK_LN(p), BLK_NB(p), (BLK_NB(p)==1)?"":"s", ctime(&BLK_TM(p)) ); printbytes(p+EXTRABYTES,BLK_NB(p)); p = BLK_FL(p); if (flip) { p2 = BLK_FL(p2); } else { if (p == p2) { mlcprintf("BLK_FL loop\n"); break; } } flip = ! flip; } #endif } #endif /* USE_MALLOC */