christos@theory.TC.Cornell.EDU (Christos S. Zoulas) (06/15/91)
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@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@ee.cornell.edu | Cornell University, Ithaca NY 14853. christos@crnlee.bitnet | Phone: (607) 255 0302, Fax: (607) 255 9072