dmuck0.15-beta/docs/muf/
dmuck0.15-beta/game/
dmuck0.15-beta/game/logs/
dmuck0.15-beta/game/muf/
dmuck0.15-beta/game/muf/text/
#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 */