home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume21
/
malloc-debug
/
part01
next >
Wrap
Text File
|
1991-07-25
|
45KB
|
2,026 lines
Newsgroups: comp.sources.misc
From: Brandon S. Allbery KF8NH <allbery@NCoast.ORG>
Subject: v21i041: malloc-debug - Debugging malloc package, Part01/01
Message-ID: <1991Jul25.024036.28795@sparky.IMD.Sterling.COM>
X-Md4-Signature: 653244e446b6a32e5d8b5f3545ca4ba5
Date: Thu, 25 Jul 1991 02:40:36 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: Brandon S. Allbery KF8NH <allbery@NCoast.ORG>
Posting-number: Volume 21, Issue 41
Archive-name: malloc-debug/part01
Environment: UNIX
[ This supersedes X-Archive: comp.sources.misc/8707/59 -Kent+ ]
Some years ago, I posted a debugging malloc package to the net. This is the
latest version of that package.
Features:
* Catches writes to either side of malloc'ed memory.
* Checks the malloc pool for consistency on each call to malloc, free, realloc,
or calloc; prints a diagnostic dump if the pool is corrupted.
* User checks can be made by calling _mallchk("string ID").
* If MALLOC_TRACEBACK is defined, a stack trace will be printed when the pool
check fails. Since the stack is often irrecoverably corrupted by the time
a core file is generated, this traceback can sometimes be the only way to
find out where the error was detected. Only tested on 386 SVR3.[12].
* Traps SIGBUS and SIGSEGV and dumps the malloc pool; these often indicate
"wild" pointers.
* Environment $MALLOC_OPTS controls tracing:
'v' trace entry/exit of functions
't' stack traceback (if MALLOC_TRACEBACK) of functions
'V' trace entry/exit of utility functions
'T' stack traceback of utility functions
'm' fault program if malloc(0) or realloc(*, 0) called
'b' print details on allocated blocks
'f' fault program on free(0)
'u' attempt to release free()'d memory to system with sbrk()
'r' fault program if realloc(0, ...)
'S' dump malloc pool on SIGSEGV
'B' dump malloc pool on SIGBUS
* Provides alternate versions of several utility functions if MALLOC_LIB is
defined; these functions will trap many "wild pointer" or off-by-one errors
before they trash memory, and will provide an immediate indication of the
location of such bugs.
++Brandon
-------------------------------------------------------------------------------
# This is a shell archive. Save this into a file, edit it
# and delete all lines above this comment. Then give this
# file to sh by executing the command "sh file". The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
# malloc.c malloc.h malltest.c
#
echo 'x - malloc.c'
sed 's/^X//' <<'________This_Is_The_END________' >>malloc.c
X/*
X * malloc for debugging -- allocates via sbrk and tracks stuff, does diag dump
X * if things appear to be screwed up
X */
X
X#include <signal.h>
X#include <fcntl.h>
X#include "malloc.h"
X
X#ifndef MALLOC_DEFAULT
X#define MALLOC_DEFAULT 0
X#endif
X
X#ifndef MALLOC_LIMIT
X#define MALLOC_LIMIT (char *) 0x80000000
X#endif
X
X#ifndef sigbase_t
X#define sigbase_t void
X#endif
X
Xtypedef sigbase_t (*sighand_t)();
X
X#define PTRC(x) ((long) (char *) (x))
X
X#ifdef __STDC__
Xextern char *sbrk(int);
Xextern char *getenv(const char *);
Xextern long strtol(const char *, char **, int);
Xextern int kill(int, int);
Xextern int getpid(void);
Xextern int open(const char *, int, int);
Xextern int write(int, const char *, int);
X#else
Xextern char *sbrk();
Xextern char *getenv();
Xextern long strtol();
Xextern int kill();
Xextern int getpid();
Xextern int open();
Xextern int write();
X#endif
Xextern char etext[];
Xextern char edata[];
Xextern char end[];
X
X#define SBRK_FAIL ((char *) -1)
X#define MAGIC_COOKIE 0xa5271009
X#define FENCE_COOKIE 0xe4057492
X#define ARR_BYTES 8
X#define FENCE (sizeof (long))
X#define DPTR(blk) ((char *) (blk)->m_blk)
Xstatic long __f__;
X#define BLKFENCE(blk) \
X (memcpy((char *) &__f__, DPTR(blk) + (blk)->m_rsize, FENCE), __f__)
X#define SET_BLKFENCE(b) \
X (__f__=FENCE_COOKIE,memcpy(DPTR(blk)+(blk)->m_rsize,(char *)&__f__,FENCE))
X#define BLKSIZE(blk) \
X (PTRC(DPTR((struct _Dmi *) 0)) + ARR_BYTES + (blk)->m_size)
X#define BLKEND(blk) (DPTR(blk) + (blk)->m_size + ARR_BYTES)
X#define NEWBLK(n) (PTRC(DPTR((struct _Dmi *) 0)) + ARR_BYTES + (n))
X#define m_round(n) (((n) + ARR_BYTES - 1) & ~(ARR_BYTES - 1))
X
Xstruct _Dmi
X{
X long m_cookie;
X struct _Dmi *m_next;
X struct _Dmi *m_prev;
X long m_size;
X long m_rsize;
X char m_blk[ARR_BYTES + FENCE];
X};
X
X#define HEADSIZE ((sizeof(struct _Dmi)) - ARR_BYTES)
X
Xstatic struct _Dmi *_fab = 0;
Xstatic struct _Dmi *_ffb = 0;
Xstatic char *_xbrk = 0;
Xstatic long _in_malloc = 0;
Xstatic long _no_memcpy = 0;
Xstatic long _st_malloc = 0;
Xlong _mall_opt = 0;
Xstatic sighand_t old_bus = SIG_DFL;
Xstatic sighand_t old_segv = SIG_DFL;
Xstatic int _mall_fd = -1;
X#ifdef MALLOC_TRACEBACK
Xstatic int *_mall_frame;
X#endif
X
Xstatic void _mallchk();
Xstatic void _mallerr();
X
X/*
X * internal: dump a string
X */
X
Xstatic void
X_mall_open()
X{
X char buf[15];
X int c, old;
X char *cp;
X
X if (_st_malloc != getpid())
X {
X close(_mall_fd);
X _mall_fd = -1;
X }
X if (_mall_fd == -1)
X {
X if (_st_malloc || !(cp = getenv("MALLOC_LOG")))
X {
X buf[0] = 'm', buf[1] = 'a', buf[2] = buf[3] = 'l', buf[4] = 'o';
X buf[5] = 'c', buf[6] = '.', buf[12] = '\0';
X _st_malloc = getpid();
X c = 11;
X while (_st_malloc && c > 6)
X {
X buf[c--] = _st_malloc % 10 + '0';
X _st_malloc /= 10;
X }
X cp = buf;
X }
X if ((_mall_fd = open(cp,O_WRONLY|O_CREAT|O_TRUNC|O_APPEND,0666)) == -1)
X _mall_fd = 2;
X else if (_mall_fd < 3)
X {
X old = _mall_fd;
X _mall_fd = fcntl(_mall_fd, F_DUPFD, 3);
X close(old);
X }
X }
X}
X
Xstatic void
X#ifdef __STDC__
X_malldstr(const char *s)
X#else
X_malldstr(s)
X char *s;
X#endif
X{
X register long len;
X
X _mall_open();
X for (len = 0; s[len]; len++)
X ;
X write(_mall_fd, s, len);
X}
X
X/*
X * internal: write a pointer in hex without using stdio
X */
X
Xstatic void
X#ifdef __STDC__
X_malldptr(register unsigned long x)
X#else
X_malldptr(x)
X register unsigned long x;
X#endif
X{
X char buf[20];
X static const char hex[] = "0123456789abcdef";
X register unsigned long dx;
X register char *p;
X
X _mall_open();
X if (!x)
X {
X write(_mall_fd, "0x0(0)", 6);
X return;
X }
X write(_mall_fd, "0x", 2);
X p = buf;
X dx = x;
X while (x != 0)
X *p++ = hex[x % 16], x = x / 16;
X while (p != buf)
X write(_mall_fd, --p, 1);
X write(_mall_fd, "(", 1);
X p = buf;
X x = dx;
X while (x != 0)
X *p++ = hex[x % 10], x /= 10;
X while (p != buf)
X write(_mall_fd, --p, 1);
X write(_mall_fd, ")", 1);
X}
X
X#ifdef MALLOC_TRACEBACK
X
X/*
X * This is EXTREMELY NON-PORTABLE but very useful. I suggest you be familiar
X * with debugger internals before hacking on this code.
X */
X
Xstatic void
X#ifdef __STDC__
X_mall_chase(const int *stkptr)
X#else
X_mall_chase(stkptr)
X int *stkptr;
X#endif
X{
X _malldstr("traceback -\n");
X /*
X * We are given the address of an argument. Treating it as a pointer to
X * an (int), we can then take ptr[-1] to get the caller's address. To go
X * farther back, we must follow the stack frames. Basically, a stack
X * frame looks like this, with descending addresses further in the list:
X *
X * return address
X * saved frame pointer (ebp of caller)
X * local vars
X * saved registers for local register vars
X *
X * (N.B. This is for the i386/i486. Your mileage WILL differ.)
X */
X if (stkptr < (int *) &stkptr || (char *) stkptr > MALLOC_LIMIT)
X {
X _mallerr("_mall_chase", "stack corrupted - frame got ",
X (long) stkptr);
X }
X while (*stkptr)
X {
X _malldstr("pc = ");
X _malldptr(*stkptr);
X _malldstr("\n");
X if ((stkptr = (int *) stkptr[-1] + 1) < (int *) &stkptr ||
X (char *) stkptr > MALLOC_LIMIT)
X {
X _mallerr("_mall_chase", "stack corrupted - frame got ",
X (long) stkptr);
X }
X }
X _malldstr("end traceback\n");
X}
X
X#endif
X
X/*
X * dump arena; can be called externally, and is non-destructive
X */
X
Xvoid
X_malldmp()
X{
X register struct _Dmi *blk;
X long oldf, oldm;
X
X if ((oldf = _in_malloc))
X {
X _malldstr("malloc diagnostic dump\n");
X#ifdef MALLOC_TRACEBACK
X _mall_chase(_mall_frame - 1);
X#endif
X }
X _in_malloc = 0;
X oldm = _no_memcpy;
X _no_memcpy = 1;
X _malldstr("brk = ");
X _malldptr(PTRC(sbrk(0)));
X _malldstr(" xbrk = ");
X _malldptr(PTRC(_xbrk));
X _malldstr("\n_fab = ");
X _malldptr(PTRC(_fab));
X _malldstr(" _ffb = ");
X _malldptr(PTRC(_ffb));
X _malldstr(" blksiz = ");
X _malldptr(HEADSIZE);
X _malldstr("\netext = ");
X _malldptr(PTRC(etext));
X _malldstr(" edata = ");
X _malldptr(PTRC(edata));
X _malldstr(" end = ");
X _malldptr(PTRC(end));
X _malldstr("\n");
X if (!_fab)
X _malldstr("no allocated blocks\n");
X else
X {
X _malldstr("\nallocated blocks\n");
X for (blk = _fab;
X blk && PTRC(blk) >= PTRC(_xbrk) && PTRC(blk) < PTRC(sbrk(0));
X blk = blk->m_next)
X {
X _malldstr("(");
X _malldptr(PTRC(blk));
X _malldstr(") ");
X _malldptr(PTRC(blk->m_prev));
X _malldstr(" <");
X _malldptr(blk->m_rsize);
X _malldstr("/");
X _malldptr(blk->m_size);
X _malldstr("> ");
X _malldptr(PTRC(blk->m_next));
X if (MAGIC_COOKIE != blk->m_cookie)
X {
X _malldstr(" cookie==");
X _malldptr(blk->m_cookie);
X }
X if (FENCE_COOKIE != BLKFENCE(blk))
X {
X _malldstr(" fence==");
X _malldptr(BLKFENCE(blk));
X }
X _malldstr("\n");
X }
X if (blk)
X _malldstr("(subsequent block pointers corrupted)\n");
X }
X if (!_ffb)
X _malldstr("\nno free blocks\n");
X else
X {
X _malldstr("\nfree blocks\n");
X for (blk = _ffb;
X blk && PTRC(blk) >= PTRC(_xbrk) && PTRC(blk) < PTRC(sbrk(0));
X blk = blk->m_next)
X {
X _malldstr("(");
X _malldptr(PTRC(blk));
X _malldstr(") ");
X _malldptr(PTRC(blk->m_prev));
X _malldstr("< ");
X _malldptr(blk->m_size);
X _malldstr(" >");
X _malldptr(PTRC(blk->m_next));
X if (MAGIC_COOKIE != blk->m_cookie)
X {
X _malldstr("cookie==");
X _malldptr(blk->m_cookie);
X }
X _malldstr("\n");
X }
X if (blk)
X _malldstr("(subsequent block pointers corrupted)\n");
X }
X _no_memcpy = oldm;
X _in_malloc = oldf;
X}
X
X/*
X * internal error routine: print error message (without using stdio) and
X * drop core
X */
X
Xstatic void
X#ifdef __STDC__
X_mallerr(const char *fn, const char *s, long ptr)
X#else
X_mallerr(fn, s, ptr)
X char *fn, *s;
X long ptr;
X#endif
X{
X _malldstr(fn);
X _malldstr(": ");
X _malldstr(s);
X _malldptr(ptr);
X _malldstr("\n");
X _malldmp();
X signal(SIGQUIT, SIG_DFL);
X kill(getpid(), SIGQUIT);
X}
X
X/*
X * initialize stuff, we want to _malldmp() on a bus/seg error
X */
X
Xstatic void
X#ifdef __STDC__
X_mall_sig(int sig)
X#else
X_mall_sig(sig)
X int sig;
X#endif
X{
X if (sig == SIGSEGV)
X {
X _malldstr("\nsegmentation violation\n\n");
X signal(SIGSEGV, old_segv);
X }
X else if (sig == SIGBUS)
X {
X _malldstr("\nbus error\n\n");
X signal(SIGBUS, old_bus);
X }
X else if (sig == SIGSYS)
X _malldstr("\ninvalid argument\n\n");
X else {
X _malldstr("\nsignal ");
X _malldptr(sig);
X _malldstr("\n\n");
X }
X#ifdef MALLOC_TRACEBACK
X _mall_chase((int *) &sig - 1);
X#endif
X _in_malloc = 1; /* silence _mallchk's default header */
X _mallchk("signal trap");
X kill(getpid(), sig);
X}
X
Xstatic void
X_mall_init()
X{
X const char *cp;
X sighand_t tmp;
X
X if (_mall_opt & _MALL_SEGV)
X {
X tmp = old_segv;
X if ((old_segv = signal(SIGSEGV, _mall_sig)) == _mall_sig)
X old_segv = tmp;
X }
X if (_mall_opt & _MALL_BUS)
X {
X tmp = old_bus;
X if ((old_bus = signal(SIGBUS, _mall_sig)) == _mall_sig)
X old_bus = tmp;
X }
X if (_st_malloc)
X return;
X _mall_opt = MALLOC_DEFAULT;
X if ((cp = getenv("MALLOC_OPTS")))
X {
X while (*cp)
X {
X switch (*cp)
X {
X case 'v':
X _mall_opt ^= _MALL_VFUNC;
X break;
X#ifdef MALLOC_TRACEBACK
X case 't':
X _mall_opt ^= _MALL_TFUNC;
X break;
X#endif
X#ifdef MALLOC_LIB
X case 'V':
X _mall_opt ^= _MALL_VUTIL;
X break;
X#ifdef MALLOC_TRACEBACK
X case 'T':
X _mall_opt ^= _MALL_TUTIL;
X break;
X#endif
X#endif
X case 'm':
X _mall_opt ^= _MALL_MALLOC_0;
X break;
X case 'b':
X _mall_opt ^= _MALL_VBLK;
X break;
X case 'f':
X _mall_opt ^= _MALL_FREE_0;
X break;
X case 'u':
X _mall_opt ^= _MALL_UNBREAK;
X break;
X case 'r':
X _mall_opt ^= _MALL_REALLOC_0;
X break;
X case 'S':
X if ((_mall_opt ^= _MALL_SEGV) & _MALL_SEGV)
X {
X tmp = old_segv;
X if ((old_segv = signal(SIGSEGV, _mall_sig))
X == _mall_sig)
X old_segv = tmp;
X }
X else
X {
X if ((tmp = signal(SIGSEGV, old_segv)) != _mall_sig)
X signal(SIGSEGV, tmp);
X }
X break;
X case 'B':
X if ((_mall_opt ^= _MALL_BUS) & _MALL_BUS)
X {
X tmp = old_bus;
X if ((old_bus = signal(SIGBUS, _mall_sig)) == _mall_sig)
X old_bus = tmp;
X }
X else
X {
X if ((tmp = signal(SIGBUS, old_bus)) != _mall_sig)
X signal(SIGBUS, tmp);
X }
X break;
X default:
X break;
X }
X cp++;
X }
X }
X _st_malloc = getpid();
X}
X
X/*
X * figure out which allocation block this pointer came from
X * return NULL if none
X */
X
Xstatic struct _Dmi *
X#ifdef __STDC__
X_mallgb(const char *s)
X#else
X_mallgb(s)
X char *s;
X#endif
X{
X register struct _Dmi *blk;
X
X for (blk = _fab; blk; blk = blk->m_next)
X {
X if (blk->m_blk == s)
X break;
X }
X return blk;
X}
X
X/*
X * _mallchk() is global, so external routines can do discreet checks on the
X * arena. If the arena is detectably corrupted, it will abort().
X */
X
Xvoid
X#ifdef __STDC__
X_mallchk(const char *fn)
X#else
X_mallchk(fn)
X char *fn;
X#endif
X{
X register struct _Dmi *blk, *cblk;
X register char *send;
X register long cnt;
X long oldm;
X#ifdef MALLOC_TRACEBACK
X int *stkptr;
X#endif
X
X if (!_in_malloc && (_mall_opt & _MALL_VFUNC))
X {
X _malldstr("called _mallchk(");
X _malldptr((long) fn);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase((int *) &fn - 1);
X#endif
X }
X oldm = _no_memcpy;
X _no_memcpy = 1;
X#ifdef MALLOC_TRACEBACK
X if ((stkptr = (int *) &fn - 1) < (int *) &stkptr ||
X (char *) stkptr > MALLOC_LIMIT)
X {
X _mallerr("mallchk", "stack corrupted - frame got ", (long) stkptr);
X }
X while (*stkptr)
X {
X if ((stkptr = (int *) stkptr[-1] + 1) < (int *) &stkptr ||
X (char *) stkptr > MALLOC_LIMIT)
X {
X _mallerr("mallchk", "stack corrupted - frame got ", (long) stkptr);
X }
X }
X#endif
X send = sbrk(0);
X cblk = 0;
X for (blk = _fab; blk; cblk = blk, blk = blk->m_next)
X {
X if (PTRC(blk) < PTRC(_xbrk) || PTRC(blk) >= PTRC(send))
X {
X _mallerr(fn, "allocated block list corrupted: blkptr = ",
X (long) blk);
X }
X if (blk->m_cookie != MAGIC_COOKIE)
X {
X _mallerr(fn, "allocated block list corrupted, bad magic cookie: ",
X blk->m_cookie);
X }
X if (blk->m_prev != cblk)
X {
X _mallerr(fn, "allocated block list corrupted: bad backptr blk ",
X (long) blk);
X }
X if (blk->m_size < 0)
X {
X _mallerr(fn, "allocated block list corrupted: blk->m_size = ",
X blk->m_size);
X }
X if (blk->m_rsize < 0)
X {
X _mallerr(fn, "allocated block list corrupted: blk->m_rsize = ",
X blk->m_rsize);
X }
X /* one for this block, one for the failed potential next block */
X if (blk->m_rsize <= blk->m_size - 2 * NEWBLK(ARR_BYTES))
X {
X _mallerr(fn, "allocated block list corrupted: rsize too small = ",
X blk->m_rsize);
X }
X if (blk->m_rsize > blk->m_size)
X {
X _mallerr(fn, "allocated block list corrupted: rsize too big = ",
X blk->m_rsize);
X }
X if (BLKFENCE(blk) != FENCE_COOKIE)
X {
X _mallerr(fn, "allocated block list corrupted, bad fence cookie: ",
X BLKFENCE(blk));
X }
X }
X cblk = 0;
X for (blk = _ffb; blk; cblk = blk, blk = blk->m_next)
X {
X if (PTRC(blk) < PTRC(_xbrk) || PTRC(blk) >= PTRC(send))
X _mallerr(fn, "free block list corrupted: blkptr = ", (long) blk);
X if (blk->m_cookie != MAGIC_COOKIE)
X {
X _mallerr(fn, "free block list corrupted, bad magic cookie",
X blk->m_cookie);
X }
X if (blk->m_prev != cblk)
X {
X _mallerr(fn, "free block list corrupted: bad backptr blk ",
X (long) blk);
X }
X if (blk->m_size < 0)
X {
X _mallerr(fn, "free block list corrupted: blk->m_size = ",
X blk->m_size);
X }
X }
X for (blk = _fab; blk; blk = blk->m_next)
X {
X if ((long) BLKEND(blk) > PTRC(send))
X {
X _malldstr("(brk = ");
X _malldptr(PTRC(send));
X _malldstr(", eblk = ");
X _malldptr((long) BLKEND(blk));
X _malldstr(")\n");
X _mallerr(fn, "allocated block extends past brk: ", (long) blk);
X }
X cnt = 0;
X for (cblk = _fab; cblk; cblk = cblk->m_next)
X {
X if (blk == cblk)
X {
X if (!cnt++)
X continue;
X _mallerr(fn, "block allocated twice: ", (long) blk);
X }
X if (blk > cblk && PTRC(blk) < (long) BLKEND(cblk))
X {
X _malldstr("(blk = ");
X _malldptr(PTRC(blk));
X _malldstr(", cblk = ");
X _malldptr(PTRC(cblk));
X _malldstr(")\n");
X _mallerr(fn, "nested block in allocated list: ", (long) blk);
X }
X }
X for (cblk = _ffb; cblk; cblk = cblk->m_next)
X {
X if (blk == cblk)
X {
X _mallerr(fn, "block on allocated and free lists: ",
X (long) blk);
X }
X if (PTRC(blk) > PTRC(cblk) && PTRC(blk) < (long) BLKEND(cblk))
X {
X _malldstr("(blk = ");
X _malldptr(PTRC(blk));
X _malldstr(", cblk = ");
X _malldptr(PTRC(cblk));
X _malldstr(", ecblk = ");
X _malldptr(PTRC(BLKEND(cblk)));
X _malldstr(")\n");
X _mallerr(fn, "alloced block nested in free block: ",
X (long) blk);
X }
X }
X }
X for (blk = _ffb; blk; blk = blk->m_next)
X {
X if ((long) BLKEND(blk) > PTRC(send))
X {
X _malldstr("(brk = ");
X _malldptr(PTRC(send));
X _malldstr(", eblk = ");
X _malldptr((long) BLKEND(blk));
X _malldstr(")\n");
X _mallerr(fn, "free block extends past brk: ", (long) blk);
X }
X cnt = 0;
X for (cblk = _ffb; cblk; cblk = cblk->m_next)
X {
X if (blk == cblk)
X {
X if (!cnt++)
X continue;
X _mallerr(fn, "block freed twice: ", (long) blk);
X }
X if (blk > cblk && PTRC(blk) < (long) BLKEND(cblk))
X {
X _malldstr("(blk = ");
X _malldptr(PTRC(blk));
X _malldstr(", cblk = ");
X _malldptr(PTRC(cblk));
X _malldstr(")\n");
X _mallerr(fn, "nested block in free list: ", (long) blk);
X }
X }
X for (cblk = _fab; cblk; cblk = cblk->m_next)
X {
X if (blk == cblk)
X {
X _mallerr(fn, "block on allocated and free lists: ",
X (long) blk);
X }
X if (blk > cblk && PTRC(blk) < (long) BLKEND(cblk))
X {
X _malldstr("(blk = ");
X _malldptr(PTRC(blk));
X _malldstr(", cblk = ");
X _malldptr(PTRC(cblk));
X _malldstr(")\n");
X _mallerr(fn, "free block nested in alloced block: ",
X (long) blk);
X }
X }
X }
X _no_memcpy = oldm;
X}
X
Xchar *
X#ifdef __STDC__
Xmalloc(unsigned int size)
X#else
Xmalloc(size)
X unsigned int size;
X#endif
X{
X register struct _Dmi *blk;
X register unsigned int n;
X
X#ifdef MALLOC_TRACEBACK
X if (!_in_malloc)
X _mall_frame = (int *) &size;
X#endif
X n = m_round(size);
X _in_malloc = 1;
X _mall_init();
X if (_mall_opt & _MALL_VFUNC)
X {
X _malldstr("called malloc(");
X _malldptr(size);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase(((int *) &size) - 1);
X#endif
X }
X _mallchk("malloc");
X if (!size)
X {
X if (_mall_opt & _MALL_MALLOC_0)
X _malldstr("warning: malloc(0) is unsafe\n");
X else
X {
X _malldstr("malloc(0) is illegal\n");
X _mall_sig(SIGSYS);
X }
X }
X for (blk = _ffb; blk; blk = blk->m_next)
X {
X if (blk->m_size >= n)
X {
X /* split a large block to save memory and enable some checking */
X if (blk->m_size >= n + NEWBLK(ARR_BYTES))
X {
X blk->m_size -= n + NEWBLK(ARR_BYTES);
X ((char *) blk) += BLKSIZE(blk);
X blk->m_cookie = MAGIC_COOKIE;
X blk->m_size = n;
X }
X else
X {
X if (blk->m_next)
X blk->m_next->m_prev = blk->m_prev;
X if (blk->m_prev)
X blk->m_prev->m_next = blk->m_next;
X if (blk == _ffb)
X _ffb = blk->m_next;
X }
X blk->m_next = _fab;
X blk->m_prev = 0;
X blk->m_rsize = size;
X SET_BLKFENCE(blk);
X if (_fab)
X _fab->m_prev = blk;
X _fab = blk;
X _in_malloc = 0;
X if (_mall_opt & _MALL_VBLK)
X {
X _malldstr("returned block ");
X _malldptr((long) blk);
X _malldstr(" user ptr ");
X _malldptr((long) blk->m_blk);
X _malldstr("\n");
X }
X return blk->m_blk;
X }
X }
X if ((char *) (blk = (struct _Dmi *) sbrk(NEWBLK(n))) == SBRK_FAIL)
X {
X _in_malloc = 0;
X if (_mall_opt & _MALL_VBLK)
X {
X _malldstr("returned failure\n");
X }
X return 0; /* no space */
X }
X if (!_xbrk)
X _xbrk = (char *) blk;
X blk->m_next = _fab;
X blk->m_prev = 0;
X blk->m_cookie = MAGIC_COOKIE;
X blk->m_size = n;
X blk->m_rsize = size;
X SET_BLKFENCE(blk);
X if (_fab)
X _fab->m_prev = blk;
X _fab = blk;
X _in_malloc = 0;
X if (_mall_opt & _MALL_VBLK)
X {
X _malldstr("returned block ");
X _malldptr((long) blk);
X _malldstr(" user ptr ");
X _malldptr((long) blk->m_blk);
X _malldstr("\n");
X }
X return blk->m_blk;
X}
X
Xvoid
X#ifdef __STDC__
Xfree(char *s)
X#else
Xfree(s)
X char *s;
X#endif
X{
X register struct _Dmi *blk, *fblk, *cblk;
X int didit;
X
X#ifdef MALLOC_TRACEBACK
X if (!_in_malloc)
X _mall_frame = (int *) &s;
X#endif
X _in_malloc = 1;
X _mall_init();
X if (_mall_opt & _MALL_VFUNC)
X {
X _malldstr("called free(");
X _malldptr(PTRC(s));
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase(((int *) &s) - 1);
X#endif
X }
X _mallchk("free");
X if (!s)
X {
X if (_mall_opt & _MALL_FREE_0)
X {
X _malldstr("warning: free(0) is unsafe\n");
X _in_malloc = 0;
X return;
X }
X else
X {
X _malldstr("free(0) is illegal\n");
X _mall_sig(SIGSYS);
X }
X }
X if (!(blk = _mallgb(s)))
X _mallerr("non-allocated pointer passed to free(): ", s, 0);
X if (blk->m_prev)
X blk->m_prev->m_next = blk->m_next;
X if (blk->m_next)
X blk->m_next->m_prev = blk->m_prev;
X if (blk == _fab)
X _fab = blk->m_next;
X blk->m_prev = 0;
X blk->m_next = _ffb;
X if (_ffb)
X _ffb->m_prev = blk;
X _ffb = blk;
X/*
X * crunch the free list by coalescing consecutive free blocks
X */
X didit = 1;
X while (didit)
X {
X didit = 0;
X for (fblk = _ffb; fblk; fblk = fblk->m_next)
X {
X for (cblk = _ffb; cblk; cblk = cblk->m_next)
X {
X if (cblk == fblk)
X continue;
X if (PTRC(fblk) + BLKSIZE(fblk) == PTRC(cblk))
X {
X fblk->m_size += BLKSIZE(cblk);
X if (cblk->m_prev)
X cblk->m_prev->m_next = cblk->m_next;
X if (cblk->m_next)
X cblk->m_next->m_prev = cblk->m_prev;
X if (_ffb == cblk)
X _ffb = cblk->m_next;
X didit = 1;
X fblk = 0;
X break;
X }
X }
X if (!fblk)
X break; /* force a recycle, since we zapped the chain */
X }
X }
X if (!(_mall_opt & _MALL_UNBREAK))
X {
X _in_malloc = 0;
X return;
X }
X for (fblk = _ffb; fblk; fblk = fblk->m_next)
X {
X if ((long) BLKEND(fblk) == PTRC(sbrk(0)))
X {
X if (fblk->m_next)
X fblk->m_next->m_prev = fblk->m_prev;
X if (fblk->m_prev)
X fblk->m_prev->m_next = fblk->m_next;
X if (fblk == _ffb)
X _ffb = fblk->m_next;
X sbrk(- fblk->m_size);
X break; /* this can only happen once */
X }
X }
X _in_malloc = 0;
X}
X
Xchar *
X#ifdef __STDC__
Xrealloc(char *s, unsigned int size)
X#else
Xrealloc(s, size)
X char *s;
X unsigned int size;
X#endif
X{
X register char *s1, *d, *d1;
X register struct _Dmi *blk;
X
X if (_mall_opt & _MALL_VFUNC)
X {
X _malldstr("called realloc(");
X _malldptr(PTRC(s));
X _malldstr(", ");
X _malldptr(size);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase(((int *) &s) - 1);
X#endif
X }
X _mallchk("realloc");
X if (!s)
X {
X if (_mall_opt & _MALL_REALLOC_0)
X {
X _malldstr("warning: realloc(0, size) is unsafe\n");
X return malloc(size);
X }
X else
X {
X _malldstr("realloc(0, size) is illegal\n");
X _mall_sig(SIGSYS);
X }
X }
X if (!size)
X {
X if (_mall_opt & _MALL_REALLOC_0)
X _malldstr("warning: realloc(ptr, 0) is unsafe\n");
X else
X {
X _malldstr("realloc(ptr, 0) is illegal\n");
X _mall_sig(SIGSYS);
X }
X }
X if (!(blk = _mallgb(s)))
X {
X _mallerr("realloc", "non-allocated pointer passed to realloc(): ",
X (long) s);
X }
X if (!(s1 = malloc(size)))
X return 0;
X if (blk->m_size < size)
X size = blk->m_size;
X d1 = s1;
X d = s;
X while (size--)
X *((char *) d1)++ = *((char *) d)++;
X free(s);
X return s1;
X}
X
X/*
X * malloc objects and zero storage
X */
X
Xchar *
X#ifdef __STDC__
Xcalloc(unsigned int n, unsigned int size)
X#else
Xcalloc(n, size)
X unsigned int n, size;
X#endif
X{
X register char *s, *s1;
X
X if (_mall_opt & _MALL_VFUNC)
X {
X _malldstr("called calloc(");
X _malldptr(n);
X _malldstr(", ");
X _malldptr(size);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase(((int *) &n) - 1);
X#endif
X }
X n *= size;
X if (!(s = malloc(n)))
X return 0;
X for (s1 = s; n; n--)
X *((char *) s1)++ = '\0';
X return s;
X}
X
X/*
X * for some reason this is in /lib/libc.a(calloc.o)
X */
X
Xvoid
X#ifdef __STDC__
Xcfree(char *s)
X#else
Xcfree(s)
X char *s;
X#endif
X{
X free(s);
X}
X
X#ifdef MALLOC_LIB
X
X/*
X * Reimplementations of some library functions that often take malloc'ed
X * pointers as arguments. The idea is that we can head off a sizeable number
X * of potential disasters before they happen, and hopefully pinpoint the
X * location of a bug a little more closely than the next operation that uses
X * malloc (or dumps core...).
X */
X
Xlong
X#ifdef __STDC__
X_mallpchk(const char *c)
X#else
X_mallpchk(c)
X char *c;
X#endif
X{
X struct _Dmi *d; /* I'd like this to be register, but... */
X
X if (!_in_malloc && (_mall_opt & _MALL_VFUNC))
X {
X _malldstr("called _mallpchk(");
X _malldptr((long) c);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase((int *) &c - 1);
X#endif
X }
X if (c == 0)
X {
X _malldstr("mallpchk(");
X _malldptr((long) c);
X _malldstr(") null\n");
X return -1;
X }
X /*
X * Theory: things shouldn't stomp on segments they don't belong to.
X * After all, how often does a data segment variable extend into bss?
X */
X if (c < etext)
X return (long) etext - (long) c;
X if (c < edata)
X return (long) edata - (long) c;
X if (c < end)
X return (long) end - (long) c;
X if (c < _xbrk)
X return (long) _xbrk - (long) c;
X if (c >= sbrk(0) && c < (char *) &d)
X {
X _malldstr("mallpchk(");
X _malldptr((long) c);
X _malldstr(") ptr outside brk\n");
X return -1;
X }
X if (c >= (char *) &d && c <= MALLOC_LIMIT)
X {
X#ifndef MALLOC_TRACEBACK
X return (long) MALLOC_LIMIT - (long) c;
X#else
X int *stkptr;
X
X if ((stkptr = (int *) &c - 1) < (int *) &d ||
X (char *) stkptr > MALLOC_LIMIT)
X {
X _mallerr("mallpchk", "stack corrupted - frame got ",
X (long) stkptr);
X }
X while (*stkptr)
X {
X if ((long) c >= (long) stkptr && (long) c < stkptr[-1])
X return (long) c + (long) stkptr - stkptr[-1] - 1;
X if ((stkptr = (int *) stkptr[-1] + 1) < (int *) &d ||
X (char *) stkptr > MALLOC_LIMIT)
X {
X _mallerr("mallpchk", "stack corrupted - frame got ",
X (long) stkptr);
X }
X }
X if (c > (char *) stkptr) /* environ[] or argv[] */
X return MALLOC_LIMIT - (char *) stkptr;
X _malldstr("mallpchk(");
X _malldptr((long) c);
X _malldstr(") stack is damaged\n");
X return -1;
X#endif
X }
X if (c >= MALLOC_LIMIT)
X {
X _malldstr("mallpchk(");
X _malldptr((long) c);
X _malldstr(") ptr outside address space\n");
X return -1;
X }
X for (d = _fab; d; d = d->m_next)
X {
X if (c >= d->m_blk && c < d->m_blk + d->m_size)
X return d->m_size + (long) d->m_blk - (long) c;
X }
X _malldstr("mallpchk(");
X _malldptr((long) c);
X _malldstr(") found no valid block\n");
X _malldmp();
X return -1;
X}
X
Xchar *
X#ifdef __STDC__
Xstrcpy(char *d, const char *s)
X#else
Xstrcpy(d, s)
X char *d, *s;
X#endif
X{
X register int c;
X int l, m;
X
X _mall_init();
X _in_malloc = 1;
X#ifdef MALLOC_TRACEBACK
X _mall_frame = (int *) &d;
X#endif
X if (_mall_opt & _MALL_VUTIL)
X {
X _malldstr("called strcpy(");
X _malldptr((long) d);
X _malldstr(", ");
X _malldptr((long) s);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TUTIL)
X _mall_chase(((int *) &d) - 1);
X#endif
X }
X _mallchk("strcpy");
X if (!d)
X {
X _malldstr("strcpy to null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (!s)
X {
X _malldstr("strcpy from null pointer\n");
X _mall_sig(SIGSYS);
X }
X if ((m = _mallpchk(d)) < 0)
X {
X _malldstr("strcpy to invalid addr ");
X _malldptr((long) d);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X if ((l = _mallpchk(s)) < 0)
X {
X _malldstr("strcpy from invalid addr ");
X _malldptr((long) s);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X for (c = 0; s[c]; c++)
X {
X if (c == l)
X {
X _malldstr("strcpy src ");
X _malldptr((long) s);
X _malldstr(" too long\n");
X _mall_sig(SIGSYS);
X }
X if (c == m)
X {
X _malldstr("strcpy dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X d[c] = s[c];
X }
X if (c == m)
X {
X _malldstr("strcpy dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X d[c] = 0;
X _in_malloc = 0;
X return d;
X}
X
Xchar *
X#ifdef __STDC__
Xstrncpy(char *d, const char *s, int n)
X#else
Xstrncpy(d, s, n)
X char *d, *s;
X int n;
X#endif
X{
X register int c;
X int l, m;
X
X _mall_init();
X _in_malloc = 1;
X#ifdef MALLOC_TRACEBACK
X _mall_frame = (int *) &d;
X#endif
X if (_mall_opt & _MALL_VUTIL)
X {
X _malldstr("called strncpy(");
X _malldptr((long) d);
X _malldstr(", ");
X _malldptr((long) s);
X _malldstr(", ");
X _malldptr(n);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TUTIL)
X _mall_chase(((int *) &d) - 1);
X#endif
X }
X _mallchk("strncpy");
X if (!d)
X {
X _malldstr("strncpy to null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (!s)
X {
X _malldstr("strncpy from null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (n < 0)
X {
X _malldstr("strncpy(dest, src, ");
X _malldptr(n);
X _malldstr(") negative count\n");
X _mall_sig(SIGSYS);
X }
X if ((m = _mallpchk(d)) < 0)
X {
X _malldstr("strncpy to invalid addr ");
X _malldptr((long) d);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X if (m < n)
X {
X _malldstr("strncpy dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X if ((l = _mallpchk(s)) < 0)
X {
X _malldstr("strncpy from invalid addr ");
X _malldptr((long) s);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X for (c = 0; s[c] && n--; c++)
X {
X if (c == l)
X {
X _malldstr("strncpy src ");
X _malldptr((long) s);
X _malldstr(" too long\n");
X _mall_sig(SIGSYS);
X }
X d[c] = s[c];
X }
X while (n--)
X d[c++] = 0;
X _in_malloc = 0;
X return d;
X}
X
Xchar *
X#ifdef __STDC__
Xstrcat(char *d, const char *s)
X#else
Xstrcat(d, s)
X char *d, *s;
X#endif
X{
X register int c, a;
X int l, m;
X
X _mall_init();
X _in_malloc = 1;
X#ifdef MALLOC_TRACEBACK
X _mall_frame = (int *) &d;
X#endif
X if (_mall_opt & _MALL_VUTIL)
X {
X _malldstr("called strcat(");
X _malldptr((long) d);
X _malldstr(", ");
X _malldptr((long) s);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TUTIL)
X _mall_chase(((int *) &d) - 1);
X#endif
X }
X _mallchk("strcat");
X if (!d)
X {
X _malldstr("strcat to null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (!s)
X {
X _malldstr("strcat from null pointer\n");
X _mall_sig(SIGSYS);
X }
X if ((m = _mallpchk(d)) < 0)
X {
X _malldstr("strcat to invalid addr ");
X _malldptr((long) d);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X if ((l = _mallpchk(s)) < 0)
X {
X _malldstr("strcat from invalid addr ");
X _malldptr((long) s);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X for (a = 0; a < m && d[a]; a++)
X ;
X if (a == m)
X {
X _malldstr("strcat dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X for (c = 0; s[c]; c++)
X {
X if (c == l)
X {
X _malldstr("strcat src ");
X _malldptr((long) s);
X _malldstr(" too long\n");
X _mall_sig(SIGSYS);
X }
X if (c + a == m)
X {
X _malldstr("strcat dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X d[c + a] = s[c];
X }
X if (c + a == m)
X {
X _malldstr("strcat dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X d[c + a] = 0;
X _in_malloc = 0;
X return d;
X}
X
Xchar *
X#ifdef __STDC__
Xstrncat(char *d, const char *s, int n)
X#else
Xstrncat(d, s, n)
X char *d, *s;
X int n;
X#endif
X{
X register int c, a;
X int l, m;
X
X _mall_init();
X _in_malloc = 1;
X#ifdef MALLOC_TRACEBACK
X _mall_frame = (int *) &d;
X#endif
X if (_mall_opt & _MALL_VUTIL)
X {
X _malldstr("called strncat(");
X _malldptr((long) d);
X _malldstr(", ");
X _malldptr((long) s);
X _malldstr(", ");
X _malldptr(n);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TUTIL)
X _mall_chase(((int *) &d) - 1);
X#endif
X }
X _mallchk("strncat");
X if (!d)
X {
X _malldstr("strncat to null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (!s)
X {
X _malldstr("strncat from null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (n < 0)
X {
X _malldstr("strncat(dest, src, ");
X _malldptr(n);
X _malldstr(") negative count\n");
X _mall_sig(SIGSYS);
X }
X if ((m = _mallpchk(d)) < 0)
X {
X _malldstr("strncat to invalid addr ");
X _malldptr((long) d);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X for (a = 0; a < m && d[a]; a++)
X ;
X if (a + n > m)
X {
X _malldstr("strncat dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X if ((l = _mallpchk(s)) < 0)
X {
X _malldstr("strncat from invalid addr ");
X _malldptr((long) s);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X for (c = 0; s[c] && n--; c++)
X {
X if (c == l)
X {
X _malldstr("strncat src ");
X _malldptr((long) s);
X _malldstr(" too long\n");
X _mall_sig(SIGSYS);
X }
X d[c + a] = s[c];
X }
X while (n--)
X d[c++ + a] = 0;
X _in_malloc = 0;
X return d;
X}
X
Xchar *
X#ifdef __STDC__
Xmemcpy(char *d, const char *s, int n)
X#else
Xmemcpy(d, s, n)
X char *d, *s;
X int n;
X#endif
X{
X register int c;
X int l, m, o;
X
X if (!(o = _in_malloc) && !_no_memcpy)
X {
X _mall_init();
X _in_malloc = 1;
X#ifdef MALLOC_TRACEBACK
X _mall_frame = (int *) &d;
X#endif
X if (_mall_opt & _MALL_VUTIL)
X {
X _malldstr("called memcpy(");
X _malldptr((long) d);
X _malldstr(", ");
X _malldptr((long) s);
X _malldstr(", ");
X _malldptr(n);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TUTIL)
X _mall_chase(((int *) &d) - 1);
X#endif
X }
X _mallchk("memcpy");
X if (!d)
X {
X _malldstr("memcpy to null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (!s)
X {
X _malldstr("memcpy from null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (n < 0)
X {
X _malldstr("memcpy(dest, src, ");
X _malldptr(n);
X _malldstr(") negative count\n");
X _mall_sig(SIGSYS);
X }
X if ((m = _mallpchk(d)) < 0)
X {
X _malldstr("memcpy to invalid addr ");
X _malldptr((long) d);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X if (m < n)
X {
X _malldstr("memcpy dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X if ((l = _mallpchk(s)) < 0)
X {
X _malldstr("memcpy from invalid addr ");
X _malldptr((long) s);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X if (l < n)
X {
X _malldstr("memcpy src ");
X _malldptr((long) s);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X }
X for (c = 0; n--; c++)
X d[c] = s[c];
X _in_malloc = o;
X return d;
X}
X
Xchar *
X#ifdef __STDC__
Xmemset(char *d, int s, int n)
X#else
Xmemset(d, s, n)
X char *d;
X int s, n;
X#endif
X{
X register int c;
X int m;
X
X _mall_init();
X _in_malloc = 1;
X#ifdef MALLOC_TRACEBACK
X _mall_frame = (int *) &s;
X#endif
X if (_mall_opt & _MALL_VUTIL)
X {
X _malldstr("called memset(");
X _malldptr((long) d);
X _malldstr(", ");
X _malldptr(s);
X _malldstr(", ");
X _malldptr(n);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TUTIL)
X _mall_chase(((int *) &d) - 1);
X#endif
X }
X _mallchk("memset");
X if (!d)
X {
X _malldstr("memset to null pointer\n");
X _mall_sig(SIGSYS);
X }
X if (n < 0)
X {
X _malldstr("memset(dest, src, ");
X _malldptr(n);
X _malldstr(") negative count\n");
X _mall_sig(SIGSYS);
X }
X if ((m = _mallpchk(d)) < 0)
X {
X _malldstr("memset to invalid addr ");
X _malldptr((long) d);
X _malldstr("\n");
X _mall_sig(SIGSYS);
X }
X if (m < n)
X {
X _malldstr("memset dest ");
X _malldptr((long) d);
X _malldstr(" too short\n");
X _mall_sig(SIGSYS);
X }
X for (c = 0; n--; c++)
X d[c] = s;
X _in_malloc = 0;
X return d;
X}
X
X/*
X * Validate a STDIO pointer. User-invoked diagnostic routine, I am not
X * going to rewrite stdio just to do pointer checks!
X */
X
X#include <stdio.h>
X
Xvoid
X_mallschk(fp)
X FILE *fp;
X{
X if (_mall_opt & _MALL_VFUNC)
X {
X _malldstr("called _mallschk(");
X _malldptr((long) fp);
X _malldstr(")\n");
X#ifdef MALLOC_TRACEBACK
X if (_mall_opt & _MALL_TFUNC)
X _mall_chase((int *) &fp - 1);
X#endif
X }
X _in_malloc = 1;
X if (_mallpchk((char *) fp) == -1)
X _mallerr("mallschk", "stdio FILE * out of range", (long) fp);
X _malldstr("stdio ptr ");
X _malldptr((long) fp);
X _malldstr(" {ptr=");
X _malldptr((long) fp->_ptr);
X _malldstr(", cnt=");
X _malldptr((long) fp->_cnt);
X _malldstr(", base=");
X _malldptr((long) fp->_base);
X _malldstr(", bufend=");
X _malldptr((long) _bufend(fp));
X _malldstr(", file=");
X _malldptr((long) fp->_file);
X _malldstr(", flag=");
X _malldptr((long) fp->_flag);
X _malldstr("}\n");
X if (_mallpchk((char *) fp->_ptr) == -1)
X _mallerr("mallschk", "stdio buf ptr out of range", (long) fp->_ptr);
X if (_mallpchk((char *) fp->_base) == -1)
X _mallerr("mallschk", "stdio base ptr out of range", (long) fp->_base);
X if (_mallpchk((char *) _bufend(fp)) == -1)
X {
X _mallerr("mallschk", "stdio bufend ptr out of range",
X (long) _bufend(fp));
X }
X if (fp->_base + fp->_cnt >= _bufend(fp))
X _mallerr("mallschk", "stdio bufcnt out of range", fp->_cnt);
X _in_malloc = 0;
X}
X
X#endif
________This_Is_The_END________
echo 'x - malloc.h'
sed 's/^X//' <<'________This_Is_The_END________' >>malloc.h
X/*
X * malloc for debugging -- allocates via sbrk and tracks stuff, does diag dump
X * if things appear to be screwed up. (bsa)
X */
X
X#if defined(__STDC__)
Xextern void _malldmp(void);
Xextern char *malloc(unsigned int);
Xextern void free(char *);
Xextern char *realloc(char *, unsigned int);
Xextern void _mallchk(const char *);
Xextern char *calloc(unsigned int, unsigned int);
Xextern void cfree(char *);
Xextern char *strcpy(char *, const char *);
Xextern char *strncpy(char *, const char *, int);
Xextern char *strcat(char *, const char *);
Xextern char *strncat(char *, const char *, int);
Xextern char *memcpy(char *, const char *, int);
Xextern char *memset(char *, int, int);
X#else
Xextern void _malldmp();
Xextern char *malloc();
Xextern void free();
Xextern char *realloc();
Xextern void _mallchk();
Xextern char *calloc();
Xextern void cfree();
Xextern char *strcpy();
Xextern char *strncpy();
Xextern char *strcat();
Xextern char *strncat();
Xextern char *memcpy();
Xextern char *memset();
X#endif
X
X#define _MALL_VFUNC 0x00000001 /* v */
X#define _MALL_TFUNC 0x00000002 /* t */
X#define _MALL_VUTIL 0x00000004 /* V */
X#define _MALL_TUTIL 0x00000008 /* T */
X#define _MALL_MALLOC_0 0x00000010 /* m */
X#define _MALL_VBLK 0x00000020 /* b */
X#define _MALL_FREE_0 0x00000040 /* f */
X#define _MALL_UNBREAK 0x00000080 /* u */
X#define _MALL_REALLOC_0 0x00000100 /* r */
X#define _MALL_SEGV 0x00000200 /* S */
X#define _MALL_BUS 0x00000400 /* B */
________This_Is_The_END________
echo 'x - malltest.c'
sed 's/^X//' <<'________This_Is_The_END________' >>malltest.c
X#include <stdio.h>
X
Xextern void setbuf();
Xextern char *strrchr();
Xextern char *malloc();
Xextern char *realloc();
Xextern void free();
Xextern int getopt();
Xextern void exit();
Xextern void srand48();
Xextern double drand48();
Xextern long time();
Xextern int getpid();
Xextern int printf();
Xextern int fprintf();
Xextern long strtol();
X
Xextern char *optarg;
Xextern int optind;
X
Xint
Xrnd(l, h)
X int l, h;
X{
X static int initialized = 0;
X
X if (l == h)
X return l;
X if (!initialized)
X {
X srand48(getpid() ^ time((long *) 0));
X initialized = 1;
X }
X return (int) (drand48() * (h - l + 1) + l);
X}
X
Xint
Xmain(argc, argv)
X int argc;
X char **argv;
X{
X char **allocs;
X int cnt, opt, repeats, low, high, errs, slots;
X char *myname, *cp;
X
X setbuf(stderr, (char *) 0);
X if ((myname = strrchr(argv[0], '/')))
X myname++;
X else
X myname = argv[0];
X repeats = 1;
X slots = 100;
X low = 1;
X high = 32768;
X while ((opt = getopt(argc, argv, "r:l:h:s:")) != EOF)
X {
X switch (opt)
X {
X case 'r':
X cnt = strtol(optarg, &cp, 0);
X if (cp == optarg || *cp)
X {
X fprintf(stderr, "%s: invalid number \"%s\" for -r\n", myname,
X optarg);
X errs++;
X }
X else if (cnt <= 0)
X {
X fprintf(stderr, "%s: -r repeat count must be positive\n",
X myname);
X errs++;
X }
X else
X repeats = cnt;
X break;
X case 'l':
X cnt = strtol(optarg, &cp, 0);
X if (cp == optarg || *cp)
X {
X fprintf(stderr, "%s: invalid number \"%s\" for -l\n", myname,
X optarg);
X errs++;
X }
X else if (cnt <= 0)
X {
X fprintf(stderr, "%s: -l lower limit must be positive\n",
X myname);
X errs++;
X }
X else
X low = cnt;
X break;
X case 'h':
X cnt = strtol(optarg, &cp, 0);
X if (cp == optarg || *cp)
X {
X fprintf(stderr, "%s: invalid number \"%s\" for -h\n", myname,
X optarg);
X errs++;
X }
X else if (cnt <= 0)
X {
X fprintf(stderr, "%s: -h higher limit must be positive\n",
X myname);
X errs++;
X }
X else
X high = cnt;
X break;
X case 's':
X cnt = strtol(optarg, &cp, 0);
X if (cp == optarg || *cp)
X {
X fprintf(stderr, "%s: invalid number \"%s\" for -s\n", myname,
X optarg);
X errs++;
X }
X else if (cnt <= 0)
X {
X fprintf(stderr, "%s: -s slot count must be positive\n",
X myname);
X errs++;
X }
X else
X slots = cnt;
X break;
X default:
X errs++;
X break;
X }
X }
X if (errs)
X {
X fprintf(stderr,
X "usage: malloc_test [-r repeat] [-l lowlim] [-h highlim]\n");
X exit(1);
X }
X while (repeats--)
X {
X if (!(allocs = (char **) malloc(slots * sizeof *allocs)))
X {
X fprintf(stderr, "%s: can't allocate %d slots\n", myname, slots);
X exit(1);
X }
X for (cnt = 0; cnt < slots; cnt++)
X {
X if (!(allocs[cnt] = malloc(errs = rnd(low, high))))
X {
X fprintf(stderr, "%s: can't allocate %d bytes for slot %d\n",
X myname, errs, cnt);
X exit(1);
X }
X }
X for (cnt = 0; cnt < slots; cnt++)
X {
X if (!(allocs[cnt] = realloc(allocs[cnt], errs = rnd(low, high))))
X {
X fprintf(stderr, "%s: can't reallocate %d bytes for slot %d\n",
X myname, errs, cnt);
X exit(1);
X }
X }
X for (cnt = 0; cnt < slots; cnt++)
X free(allocs[cnt]);
X free(allocs);
X }
X printf("%s: test completed successfully\n", myname);
X return 0;
X}
________This_Is_The_END________
exit
--
Me: Brandon S. Allbery KF8NH: DC to LIGHT! [44.70.4.88]
Internet: allbery@NCoast.ORG Delphi: ALLBERY
uunet!usenet.ins.cwru.edu!ncoast!allbery
exit 0 # Just in case...