YADM [Yet Another Malloc Debug]

Christos S. Zoulas christos at theory.TC.Cornell.EDU
Sat Jun 15 03:39:16 AEST 1991


Hello,

Since lots of people have been asking for this kind of library lately,
here's my shot at it. I don't claim it is better than any of the others,
but it is the one that I have been using for a long while, and it works
very well for me. I hope it proves useful to you too.


christos

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Makefile README debugalloc.c malloc.h tst.c
# Wrapped by christos at guillemin on Fri Jun 14 13:35:44 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(132 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
XSHELL	= /bin/sh
XCFLAGS	= -O -DDEBUG
X
Xtst: tst.o debugalloc.o
X	cc ${CFLAGS} tst.o debugalloc.o -o tst
X
Xclean:
X	rm -f *.o tst *.bak
END_OF_FILE
if test 132 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(281 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X
XThis is another debugging malloc library replacement. It is intended mostly
Xto help track down memory leaks, and not memory overwriting. I hope it
Xproves useful to someone.
X
XTo use just include "malloc.h" in your program, compile with -DDEBUG, and
Xlink in debugalloc.o
X
Xchristos
END_OF_FILE
if test 281 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'debugalloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'debugalloc.c'\"
else
echo shar: Extracting \"'debugalloc.c'\" \(9003 characters\)
sed "s/^X//" >'debugalloc.c' <<'END_OF_FILE'
X/* $Header: /home/hyperion/mu/christos/src/mine/lib/alloc/RCS/debugalloc.c,v 1.4 1991/05/05 02:49:43 christos Exp $ */
X/*
X *
X * debugalloc.c : Special Debug Malloc Routines
X *
X * Routines:
X *	char * 		DebugMalloc();
X *	char *		DebugCalloc();
X *	char *		DebugRealloc();
X *	void 		DebugFree();
X *	unsigned	DebugMemStat();
X *	unsigned	DebugMemPtr();
X *	void		DebugMemChain();
X *
X * $Log: debugalloc.c,v $
X * Revision 1.4  1991/05/05  02:49:43  christos
X * Fixed small lint bug
X *
X * Revision 1.3  1991/04/21  00:14:18  christos
X * Fixed free error message
X *
X * Revision 1.2  1991/02/10  00:44:07  christos
X * Added tests for pointers out of the allocated
X * range
X *
X * Revision 1.1  1991/02/01  08:12:55  christos
X * Initial revision
X *
X */
X#ifndef lint
Xstatic char rcsid[] = "$Id: debugalloc.c,v 1.4 1991/05/05 02:49:43 christos Exp $";
X#endif /* lint */
X#include <stdio.h>
X
X#ifdef __STDC__
X# include <stdlib.h>
X# include <memory.h>
X#else
Xextern char *malloc();
Xextern char *calloc();
Xextern char *realloc();
Xextern void free();
Xextern void abort();
Xextern char *memset();
Xextern void exit();
X#endif
X
X#ifndef NIL
X# define NIL(a) ((a *) 0)
X#endif /* NIL */
X
X#ifndef MIN
X# define MIN(a, b) 		((a) > (b) ? (b) : (a))
X#endif /* MIN */
X
X#ifndef MAX
X# define MAX(a, b) 		((a) < (b) ? (b) : (a))
X#endif /* MAX */
X
X#ifndef private
X# define private static
X#endif /* private */
X
X#ifndef public
X# define public 
X#endif /* public */
X
X#define SIG_GOOD	0x01020304
X#define SIG_FREE	0x04030201
X#define SIG_CHAIN	0x44332211
X#define OVERHEAD	sizeof(debug_t)
X
X
X#ifdef __STDC__
Xtypedef	void *Ptr;
X#else
Xtypedef char *Ptr;
X#endif
X
Xtypedef struct debug_t {
X    long	d_sign;
X    unsigned	long d_size;
X    char *	d_file;
X    long	d_line;
X    union {
X	struct {
X	    struct debug_t	*c_prev;
X	    struct debug_t	*c_next;
X	} d_c;
X	struct {
X	    char 		*f_file;
X	    long		f_line;
X	} d_f;
X    } d_d;
X} debug_t;
X
X#define d_next		d_d.d_c.c_next
X#define d_prev		d_d.d_c.c_prev
X#define d_ffile 	d_d.d_f.f_file
X#define d_fline 	d_d.d_f.f_line
X
X
X
Xprivate unsigned _memused = 0;
Xprivate unsigned _memalloc = 0;
Xprivate Ptr	 _memtop = (Ptr) 0;
Xprivate Ptr	 _membot = (Ptr) 0xffffffff;
Xprivate debug_t *chain;
X
X
X/* _chaini():
X *	Insert block in chain
X */
Xprivate debug_t *
X_chaini(tptr, n, fname, lineno)
Xchar **tptr;
Xunsigned n;
Xchar *fname;
Xint lineno;
X{
X    static debug_t __chain;
X    debug_t *dbg;
X
X    dbg = (debug_t *) *tptr;
X    *tptr += OVERHEAD;
X
X    if (chain == NIL(debug_t)) {
X	chain = &__chain;
X	chain->d_next = chain->d_prev = chain;
X	chain->d_sign = SIG_CHAIN;
X	chain->d_size = 0;
X	chain->d_file = NIL(char);
X	chain->d_line = 0;
X    }
X    dbg->d_sign = SIG_GOOD;
X    dbg->d_size = n;
X    dbg->d_file = fname;
X    dbg->d_line = lineno;
X    dbg->d_next = chain->d_next;
X    dbg->d_prev = chain;
X    chain->d_next->d_prev = dbg;
X    chain->d_next = dbg;
X    chain = dbg;
X    _memused += chain->d_size;
X    _memalloc++;
X    return(dbg);
X} /* end _chaini */
X
X
X/* _chaina():
X *	Allocate a block of the required size
X */
Xprivate Ptr
X_chaina(n, action, routine, fname, lineno, tptr)
Xunsigned n;
Xchar *action;
XPtr (*routine)();
Xchar *fname;
Xint lineno;
XPtr tptr;
X{
X    char *ptr;
X    debug_t *dbg;
X
X    if (tptr != (Ptr) 0 && (tptr < _membot || tptr > _memtop || 
X	((int) tptr) & 0x3)) {
X	(void) fprintf(stderr, "*** %s, %d: %s invalid pointer.\n", 
X		       fname, lineno, action);
X	abort();
X    }
X    if (n == 0) {
X	(void) fprintf(stderr, 
X		       "*** %s, %d: %s zero length block.\n", 
X		       fname, lineno, action);
X	if (tptr != (Ptr) 0) {
X	    dbg = (debug_t *) tptr;
X	    (void) _chaini((char **) &tptr, (unsigned) dbg->d_size, 
X			   dbg->d_file, (int) dbg->d_line);
X	}
X	abort();
X    }
X
X    ptr = (tptr == (Ptr) 0) ? (char *) (*routine)(n+OVERHEAD) :
X	  (*routine)(tptr, n+OVERHEAD);
X
X    _memtop = MAX((Ptr) ptr, _memtop);
X    _membot = MIN((Ptr) ptr, _membot);
X
X    if (ptr == NIL(char)) {
X	(void) fprintf(stderr, 
X	    "*** %s, %d: Out of memory in %s (current allocation %u).\n", 
X	    fname, lineno, action, n);
X	if (tptr != (Ptr) 0) {
X	    dbg = (debug_t *) tptr;
X	    (void) _chaini((char **) &tptr, (unsigned) dbg->d_size, 
X			   dbg->d_file, (int) dbg->d_line);
X	}
X	abort();
X    }
X    return((Ptr) ptr);
X} /* end _chaina */
X
X
X/* _chainf():
X *	Free block in chain
X */
Xprivate void
X_chainf(dbg, action, fname, lineno)
Xdebug_t *dbg;
Xchar *action;
Xchar *fname;
Xint lineno;
X{
X    dbg->d_sign = SIG_FREE;
X    if (chain == dbg)
X	chain = dbg->d_prev;
X    dbg->d_prev->d_next = dbg->d_next;
X    dbg->d_next->d_prev = dbg->d_prev;
X    dbg->d_ffile = fname;
X    dbg->d_fline = lineno;
X    _memused -= dbg->d_size;
X    _memalloc--;
X} /* end _chainf */
X
X
X/* _chaing():
X *	Return the debug header of a chain
X */
Xprivate debug_t *
X_chaing(ptr, action, fname, lineno)
Xchar **ptr;
Xchar *action;
Xchar *fname;
Xint lineno;
X{
X    if (*ptr == NIL(char)) {
X	(void) fprintf(stderr, "**** %s, %d: %s nil pointer.\n", 
X		       fname, lineno, action);
X	abort();
X    }
X    *ptr -= OVERHEAD;
X    if ((Ptr) *ptr < _membot || (Ptr) *ptr > _memtop || (((long) *ptr) & 0x3)) {
X	(void) fprintf(stderr, "*** %s, %d: %s invalid pointer.\n", 
X		       fname, lineno, action);
X	abort();
X    }
X    return((debug_t *) *ptr);
X} /* end _chaing */
X
X
X
X
X/* _chainc():
X *	Check block in chain
X */
Xprivate void
X_chainc(dbg, action, fname, lineno)
Xdebug_t *dbg;
Xchar *action;
Xchar *fname;
Xint lineno;
X{
X    static char *msg1 = "*** %s, %d: %s %s block";
X    static char *msg2 = " [%s, %d: %s]";
X
X    switch (dbg->d_sign) {
X    case SIG_GOOD:
X	break;
X    case SIG_FREE:
X        (void) fprintf(stderr, msg1, fname, lineno, action, "freed");
X        (void) fprintf(stderr, msg2, dbg->d_file, dbg->d_line, "allocated");
X        (void) fprintf(stderr, msg2, dbg->d_ffile, dbg->d_fline, "freed");
X	abort();
X	break;
X    default:
X        (void) fprintf(stderr, msg1, fname, lineno, action, "invalid");
X	(void) fprintf(stderr, ".\n");
X	abort();
X	break;
X    }
X} /* end _chainc */
X
X
X/* DebugMalloc():
X *	real alloc 
X */
Xpublic Ptr
XDebugMalloc(n, fname, lineno)
Xunsigned n;
Xchar *fname;
Xint lineno;
X{
X    static char *routine = "malloc";
X    Ptr ptr;
X
X    ptr = _chaina(n, routine, malloc, fname, lineno, (Ptr) 0);
X    (void) _chaini((char **) &ptr, n, fname, lineno);
X    return(ptr);
X} /* end DebugMalloc */
X
X
X/* DebugFree():
X *	free memory counting the number of bytes freed
X */
Xpublic void
XDebugFree(ptr, fname, lineno)
XPtr ptr;
Xchar *fname;
Xint lineno;
X{
X    static char *routine = "free";
X    debug_t *dbg;
X
X    dbg = _chaing((char **) &ptr, routine, fname, lineno);
X    _chainc(dbg, routine, fname, lineno);
X    _chainf(dbg, routine, fname, lineno);
X    free(ptr);
X} /* end DebugFree */
X
X
X/* DebugMemStat():
X *	return the amount of memory in use
X */
Xpublic unsigned
XDebugMemStat()
X{
X    return(_memused);
X} /* end DebugMemStat */
X
X
X/* DebugMemPtr():
X *	return the amount of memory in use
X */
Xpublic unsigned
XDebugMemPtr(ptr, fname, lineno)
XPtr ptr;
Xchar *fname;
Xint lineno;
X{
X    static char *routine = "get size";
X    debug_t *dbg;
X
X    dbg = _chaing((char **) &ptr, routine, fname, lineno);
X    _chainc(dbg, routine, fname, lineno);
X
X    return((unsigned) dbg->d_size);
X} /* end DebugMemPtr */
X
X
X/* DebugRealloc():
X *	real alloc 
X */
Xpublic Ptr
XDebugRealloc(ptr, n, fname, lineno)
XPtr ptr;
Xunsigned n;
Xchar *fname;
Xint lineno;
X{
X    static char *routine = "realloc";
X    debug_t *dbg;
X
X    dbg = _chaing((char **) &ptr, routine, fname, lineno);
X    _chainc(dbg, routine, fname, lineno);
X    _chainf(dbg, routine, fname, lineno);
X    ptr = _chaina(n, routine, realloc, fname, lineno, ptr);
X    dbg = _chaini((char **) &ptr, n, fname, lineno);
X
X    return(ptr);
X} /* end DebugRealloc */
X
X
X/* DebugCalloc():
X *	real alloc 
X */
Xpublic Ptr
XDebugCalloc(n, sz, fname, lineno)
Xunsigned n, sz;
Xchar *fname;
Xint lineno;
X{
X    static char *routine = "calloc";
X    Ptr ptr;
X
X    n *= sz;
X    ptr = _chaina(n, routine, malloc, fname, lineno, (Ptr) 0);
X    (void) _chaini((char **) &ptr, n, fname, lineno);
X    memset((char *) ptr, 0, n);
X    return(ptr);
X} /* end DebugCalloc */
X
X/* DebugMemChain():
X *	Dump the memory chain
X */
Xpublic void
XDebugMemChain()
X{
X    debug_t *dbg;
X    unsigned min, max;
X
X    max = 0x00000000;
X    min = 0xffffffff;
X
X    if (chain == NIL(debug_t) || chain->d_sign == SIG_CHAIN) {
X	(void) fprintf(stdout, "\tNo memory allocated.\n");
X	return;
X    }
X    (void) fprintf(stdout, "\tMemory Allocation Statistics.\n");
X    (void) fprintf(stdout, "\t%u bytes allocated in %u chunks.\n",
X		   _memused, _memalloc);
X    for (dbg = chain; dbg->d_sign != SIG_CHAIN; dbg = dbg->d_next);
X    (void) fprintf(stdout, "\t%8.8s %8.8s %20.20s %5.5s\n",
X		   "Address", "Size", "Filename", "Line");
X    for (dbg = dbg->d_next; dbg->d_sign != SIG_CHAIN; dbg = dbg->d_next) {
X	(void) fprintf(stdout, "\t%.8x %8d %20.20s %5d\n",
X		       dbg, dbg->d_size, dbg->d_file, dbg->d_line);
X	min = MIN(min, dbg->d_size);
X	max = MAX(max, dbg->d_size);
X    }
X    (void) fprintf(stdout, "\tMin %u Max %u Avg %u.\n", 
X		   min, max, _memused / _memalloc);
X} /* end DebugMemChain */
END_OF_FILE
if test 9003 -ne `wc -c <'debugalloc.c'`; then
    echo shar: \"'debugalloc.c'\" unpacked with wrong size!
fi
# end of 'debugalloc.c'
fi
if test -f 'malloc.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'malloc.h'\"
else
echo shar: Extracting \"'malloc.h'\" \(1860 characters\)
sed "s/^X//" >'malloc.h' <<'END_OF_FILE'
X/* $Header$ */
X/*
X * malloc.h: Debugging malloc utils.
X *
X */
X#ifndef _h_malloc
X#define _h_malloc
X
X
X#ifdef __STDC__
X# define P_(a)	a
X#else
X# define P_(a)  ()
X#endif /* __STDC__ */
X
X#ifdef __STDC__
X# ifndef _MEMALIGN_T
X#  define _MEMALIGN_T
X   typedef void *memalign_t;
X# endif /* _MEMALIGN_T */
X# ifndef _PTR_T
X#  define _PTR_T
X   typedef void *ptr_t;
X# endif /* _PTR_T */
X#else /* ! __STDC__ */
X# ifndef _PTR_T
X#  define _PTR_T
X   typedef char *ptr_t;
X# endif /* _PTR_T */
X# ifdef lint
X   /* Fool lint to believe that Malloc returns aligned pointers... */
X#  ifndef _MEMALIGN_T
X#   define _MEMALIGN_T
X    typedef union _memalign_t {
X	char a; short b; int c; long d; float e; double f; union _memalign_t *g;
X    } *memalign_t;
X#  endif /* _MEMALIGN_T */
X# else
X#  ifndef _MEMALIGN_T
X#   define _MEMALIGN_T
X    typedef char *memalign_t;
X#  endif /* _MEMALIGN_T */
X# endif /* lint */
X
X#endif /* ! __STDC__ */
X
X/*
X * Memory allocation macros
X */
X#ifdef DEBUG
X# define malloc(a)	(ptr_t) DebugMalloc(a, __FILE__, __LINE__)
X# define realloc(a, n)	(ptr_t) DebugRealloc(a, n, __FILE__, __LINE__)
X# define calloc(a, n)	(ptr_t) DebugCalloc(a, n, __FILE__, __LINE)
X# define free(a)	DebugFree(a, __FILE__, __LINE__)
X# define MemPtr(a)	DebugMemPtr(a, __FILE__, __LINE__)
X# define MemStat()	DebugMemStat()
X# define MemChain()	DebugMemChain()
X#else
X# define MemPtr(a)
X# define MemStat()
X# define MemChain()
X#endif /* DEBUG */
X
X#ifdef DEBUG
Xextern memalign_t DebugMalloc   P_((unsigned, char *, int));
Xextern memalign_t DebugCalloc   P_((unsigned, unsigned, char *, int));
Xextern memalign_t DebugRealloc  P_((ptr_t, unsigned, char *, int));
Xextern memalign_t DebugFree     P_((ptr_t, char *, int));
Xextern unsigned   DebugMemPtr   P_((ptr_t, char *, int));
Xextern unsigned   DebugMemStat  P_((void));
Xextern memalign_t DebugMemChain P_((void));
X#endif
X
X#endif /* _h_malloc */
END_OF_FILE
if test 1860 -ne `wc -c <'malloc.h'`; then
    echo shar: \"'malloc.h'\" unpacked with wrong size!
fi
# end of 'malloc.h'
fi
if test -f 'tst.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tst.c'\"
else
echo shar: Extracting \"'tst.c'\" \(2223 characters\)
sed "s/^X//" >'tst.c' <<'END_OF_FILE'
X
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X
X#ifdef __STDC__
X# include <stdlib.h>
X# include <memory.h>
X#else
Xextern char *malloc();
Xextern char *calloc();
Xextern char *realloc();
Xextern void free();
Xextern void abort();
Xextern char *memset();
Xextern void exit();
X#endif
X
X#include "malloc.h"
X
Xjmp_buf jb;
X
X
Xvoid
Xsigiot()
X{
X    signal(SIGIOT, sigiot);
X    MemChain();
X    longjmp(jb, 1);
X}
X
X
Xmain()
X{
X    char *ptr;
X
X    signal(SIGIOT, sigiot);
X
X    if (!setjmp(jb)) {
X	ptr = (char *) malloc(10);
X	(void) fprintf(stderr, "1. Malloc 10 ok\n");
X    }
X    else 
X	(void) fprintf(stderr, "1. Malloc 10 failed\n");
X
X    if (!setjmp(jb)) {
X	malloc(0);
X	(void) fprintf(stderr, "2. Malloc 0 failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "2. Malloc 0 ok\n");
X
X    if (!setjmp(jb)) {
X	realloc(0, 20);
X	(void) fprintf(stderr, "3. Realloc null failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "3. Realloc null ok\n");
X
X    if (!setjmp(jb)) {
X	realloc(ptr, 0);
X	(void) fprintf(stderr, "4. Realloc 0 failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "4. Realloc 0 ok\n");
X
X    if (!setjmp(jb)) {
X	ptr = (char *) realloc(ptr, 40);
X	(void) fprintf(stderr, "5. Realloc valid ok\n");
X    }
X    else 
X	(void) fprintf(stderr, "5. Realloc valid failed\n");
X
X    if (!setjmp(jb)) {
X	ptr = (char *) realloc(20, 40);
X	(void) fprintf(stderr, "6. Realloc invalid failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "6. Realloc invalid ok\n");
X
X    if (!setjmp(jb)) {
X	free(0);
X	(void) fprintf(stderr, "7. Free null failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "7. Free null ok\n");
X
X    if (!setjmp(jb)) {
X	free(ptr);
X	(void) fprintf(stderr, "8. Free valid ok\n");
X    }
X    else 
X	(void) fprintf(stderr, "8. Free valid failed\n");
X
X    if (!setjmp(jb)) {
X	free(20);
X	(void) fprintf(stderr, "9. Free invalid failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "9. Free invalid ok\n");
X
X    if (!setjmp(jb)) {
X	free(ptr);
X	(void) fprintf(stderr, "10. Free freed failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "10. Free freed ok\n");
X
X    if (!setjmp(jb)) {
X	realloc(ptr, 20);
X	(void) fprintf(stderr, "11. Realloc freed failed\n");
X    }
X    else 
X	(void) fprintf(stderr, "11. Realloc freed ok\n");
X    exit(0);
X}
X
END_OF_FILE
if test 2223 -ne `wc -c <'tst.c'`; then
    echo shar: \"'tst.c'\" unpacked with wrong size!
fi
# end of 'tst.c'
fi
echo shar: End of shell archive.
exit 0
-- 
Christos Zoulas         | 389 Theory Center, Electrical Engineering,
christos at ee.cornell.edu | Cornell University, Ithaca NY 14853.
christos at crnlee.bitnet  | Phone: (607) 255 0302, Fax: (607) 255 9072



More information about the Alt.sources mailing list