🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.unix.bsd
Article #6089

Re: debugging malloc for pyramid

#6089
From: Paul A Vixie
Date: Sat, 09 May 1992 22:59
408 lines
11161 bytes
>> I am looking for a malloc library with debugging 
>> features that will run on a pyramid in the UCB
>> universe. Please mail reply's.

The reply is useful to the general audience, so I'll post it and then
mail you a copy of this article.

What kind of debugging are you hoping to do?  If you're looking for a
malloc that catches data overruns, the one in BSD and Perl has that
feature but the libcc.a version usually ifdef's out the debug code for
performance reasons.

If you want one that detects overruns AND UNDERRUNS, there's a GNU
malloc available but it is labelled "beta test - real release soon"
and yet is inexplicably several years old.

If you want one that will trace your allocations and deallocations
(useful for finding memory leaks), please find it below.  this has
not been released to comp.sources.unix yet since i'm lazy...

#! /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:  README Makefile dmalloc.c dmalloc.h dmt.c
# Wrapped by vixie@cognition.pa.dec.com on Sat May  9 22:58:32 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1183 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
dmalloc - debugging wrapper around malloc(3)
paul vixie (@decwrl) 9 may 1992 [released]
X
normal usage is an enabling macro called DMALLOC (either -DMALLOC in your
Makefile, or "#define DMALLOC" in *all* your .c files (or some .h file
included in all your .c files).  then, in each c (or in the "big" .h):
X
X#ifdef DMALLOC
X#include "dmalloc.h"
X#else
char *malloc(), *calloc(), *realloc();
void free();
X#endif
X
look at (and build, and run) dmt.c to see what it does, which is sortof:
X
X% make dmt
gcc -O -c dmt.c
gcc -O -c dmalloc.c
gcc -o dmt dmt.o dmalloc.o
X% cat dmt.c
X#include <stdio.h>
X#include "dmalloc.h"
X
main() {
X        char *m1 = malloc(41);
X        char *m2 = malloc(52);
X        char *m3 = malloc(63);
X
X        dmallocstats(stdout);
X        free(m2);
X        dmallocstats(stdout);
X}
X% ./dmt
dallocstats [ private mem used=3172, avail=62364 ]
X        "dmt.c":7 calls=1 blocks=1 bytes=63
X        "dmt.c":6 calls=1 blocks=1 bytes=52
X        "dmt.c":5 calls=1 blocks=1 bytes=41
dallocstats [ private mem used=4224, avail=61312 ]
X        "dmt.c":7 calls=1 blocks=1 bytes=63
X        "dmt.c":6 calls=1
X                "dmt.c":10 calls=1
X        "dmt.c":5 calls=1 blocks=1 bytes=41
END_OF_FILE
if test 1183 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(120 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
CC=gcc
X
all: dmalloc.o
X
dmt: dmt.o dmalloc.o
X	$(CC) -o dmt dmt.o dmalloc.o
X
clean:
X	rm -f *.o *~ *.BAK *.CKP
X	rm -f dmt
END_OF_FILE
if test 120 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'dmalloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dmalloc.c'\"
else
echo shar: Extracting \"'dmalloc.c'\" \(4808 characters\)
sed "s/^X//" >'dmalloc.c' <<'END_OF_FILE'
X/* dmalloc - debugging layer on top of malloc
X * vix 25mar92 [fixed bug in round-up calcs in alloc()]
X * vix 24mar92 [added size calcs, improved printout]
X * vix 22mar92 [written]
X */
X
X#include <stdio.h>
X#include <signal.h>
X
X#define TRUE 1
X#define FALSE 0
typedef	unsigned bool;
X
X#define	MAX_MEMORY	65536	/* must fit in typeof(datum.size) */
X#define	MAX_CALLERS	256	/* must be **2 */
X
typedef struct caller {
X	struct caller	*next;
X	struct filenam	*file;
X	struct calltab	*frees;
X	unsigned	line;
X	unsigned	calls;
X	unsigned	blocks;
X	unsigned	bytes;
X} caller;
X
typedef	struct filenam {
X	struct filenam	*next;
X	char		*name;
X} filenam;
X
typedef	struct calltab {
X	struct caller	*callers[MAX_CALLERS];
X} calltab;
X
typedef struct datum {
X	unsigned	size;		/* size of malloc'd item */
X	unsigned	caller;		/* offset into memory[] */
X	/* user data follows */
X} datum;
X
static	char	memory[MAX_MEMORY];
static	char	*nextmem = memory;
static	char	*alloc(size) unsigned size; {
X			char *thismem = nextmem;
X			int oddness = (size % sizeof(char*));
X			if (oddness)
X				size += (sizeof(char*) - oddness);
X			nextmem += size;
X			if (nextmem >= &memory[MAX_MEMORY]) {
X				fprintf(stderr, "dmalloc.alloc: out of mem\n");
X				kill(0, SIGBUS);
X			}
X			return thismem;
X		}
X
static	filenam	*Files;
static	calltab	Callers;
X
X/*--------------------------------------------------- imports
X */
X
char	*malloc(), *calloc(), *realloc();
void	free();
X
X/*--------------------------------------------------- private
X */
X
X#define	STR_EQ(l,r)	(((l)[0] == (r)[0]) && !strcmp(l, r))
X
static filenam *
findFile(file, addflag)
X	char *file;
X	bool addflag;
X{
X	filenam	*f;
X
X	for (f = Files;  f;  f = f->next)
X		if (STR_EQ(file, f->name))
X			return f;
X	if (!addflag)
X		return NULL;
X	f = (filenam*) alloc(sizeof(filenam));
X	f->next = Files;
X	Files = f;
X	f->name = alloc(strlen(file) + 1);
X	strcpy(f->name, file);
X	return f;
X}
X
static caller *
findCaller(ctab, file, line, addflag)
X	calltab *ctab;
X	char *file;
X	unsigned line;
X	bool addflag;
X{
X	unsigned hash = line & (MAX_CALLERS - 1);
X	caller *c;
X
X	for (c = ctab->callers[hash];  c;  c = c->next)
X		if ((c->line == line) && STR_EQ(c->file->name, file))
X			return c;
X	if (!addflag)
X		return NULL;
X	c = (caller*) alloc(sizeof(caller));
X	c->next = ctab->callers[hash];
X	c->file = findFile(file, TRUE);
X	c->line = line;
X	c->calls = 0;
X	c->frees = (calltab *) alloc(sizeof(calltab));
X	ctab->callers[hash] = c;
X	return c;
X}
X
X/*--------------------------------------------------- public
X */
X
char *
dmalloc(file, line, size)
X	char *file;
X	unsigned line;
X	unsigned size;
X{
X	caller *c;
X	datum *d;
X
X	c = findCaller(&Callers, file, line, TRUE);
X	d = (datum *) malloc(sizeof(datum) + size);
X	d->size = size;
X	d->caller = ((char *)c) - memory;
X	c->calls++;
X	c->blocks++;
X	c->bytes += size;
X	return (char *) (d+1);
X}
X
void
dfree(file, line, ptr)
X	char *file;
X	unsigned line;
X	char *ptr;
X{
X	caller *c, *a;
X	datum *d;
X
X	d = (datum *) ptr;  d--;
X	a = (caller *) (memory + d->caller);
X	a->bytes -= d->size;
X	a->blocks--;
X	c = findCaller(a->frees, file, line, TRUE);
X	c->calls++;
X	free((char*) d);
X}
X
char *
dcalloc(file, line, nelems, elsize)
X	char *file;
X	unsigned line;
X	unsigned nelems, elsize;
X{
X	unsigned size = (nelems * elsize);
X	char *ptr;
X
X	ptr = dmalloc(file, line, size);
X	bzero(ptr, size);
X	return ptr;
X}
X
char *
drealloc(file, line, ptr, size)
X	char *file;
X	unsigned line;
X	char *ptr;
X	unsigned size;
X{
X	caller *c, *a;
X	datum *d;
X
X	d = (datum *) ptr;  d--;
X	/* fix up stats from allocation */
X	a = (caller *) (memory + d->caller);
X	a->bytes -= d->size;
X	a->blocks--;
X	/* we are a "freer" of this allocation */
X	c = findCaller(a->frees, file, line, TRUE);
X	c->calls++;
X	/* get new allocation and stat it */
X	c = findCaller(&Callers, file, line, TRUE);
X	d = (datum *) realloc((char *) d, sizeof(datum) + size);
X	d->size = size;
X	d->caller = ((char *)c) - memory;
X	c->calls++;
X	c->blocks++;
X	c->bytes += size;
X	return (char *) (d+1);
X}
X
static void
dmalloccallers(outf, prefix, ctab)
X	FILE *outf;
X	char *prefix;
X	calltab *ctab;
X{
X	/* this bizarre logic is to print all of a file's entries together */
X	filenam	*f;
X
X	for (f = Files;  f;  f = f->next) {
X		int	i;
X
X		for (i = MAX_CALLERS-1;  i >= 0;  i--) {
X			caller *c;
X
X			for (c = ctab->callers[i];  c;  c = c->next) {
X				if (f != c->file)
X					continue;
X				fprintf(outf, "%s\"%s\":%u calls=%u",
X					prefix, c->file->name, c->line,
X					c->calls);
X				if (c->blocks || c->bytes)
X					fprintf(outf, " blocks=%u bytes=%u",
X						c->blocks, c->bytes);
X				fputc('\n', outf);
X				if (c->frees)
X					dmalloccallers(outf,
X						       "\t\t", c->frees);
X			}
X		}
X	}
X}
X
void
dmallocstats(outf)
X	FILE *outf;
X{
X	fprintf(outf, "dallocstats [ private mem used=%u, avail=%u ]\n",
X		nextmem - memory, &memory[MAX_MEMORY] - nextmem);
X	dmalloccallers(outf, "\t", &Callers);
X}
END_OF_FILE
if test 4808 -ne `wc -c <'dmalloc.c'`; then
    echo shar: \"'dmalloc.c'\" unpacked with wrong size!
fi
# end of 'dmalloc.c'
fi
if test -f 'dmalloc.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dmalloc.h'\"
else
echo shar: Extracting \"'dmalloc.h'\" \(356 characters\)
sed "s/^X//" >'dmalloc.h' <<'END_OF_FILE'
X/* dmalloc - debugging layer on top of malloc
X * vix 22mar92 [written]
X */
X
X#define	malloc(s)	dmalloc(__FILE__, __LINE__, s)
X#define	free(p)		dfree(__FILE__, __LINE__, p)
X#define	calloc(n, s)	dcalloc(__FILE__, __LINE__, n, s)
X#define	realloc(p, s)	drealloc(__FILE__, __LINE__, p, s)
X
char *dmalloc(), *dcalloc(), *drealloc();
void dfree(), dmallocstats();
END_OF_FILE
if test 356 -ne `wc -c <'dmalloc.h'`; then
    echo shar: \"'dmalloc.h'\" unpacked with wrong size!
fi
# end of 'dmalloc.h'
fi
if test -f 'dmt.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dmt.c'\"
else
echo shar: Extracting \"'dmt.c'\" \(182 characters\)
sed "s/^X//" >'dmt.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include "dmalloc.h"
X
main() {
X	char *m1 = malloc(41);
X	char *m2 = malloc(52);
X	char *m3 = malloc(63);
X
X	dmallocstats(stdout);
X	free(m2);
X	dmallocstats(stdout);
X}
END_OF_FILE
if test 182 -ne `wc -c <'dmt.c'`; then
    echo shar: \"'dmt.c'\" unpacked with wrong size!
fi
# end of 'dmt.c'
fi
echo shar: End of shell archive.
exit 0

--
Paul Vixie, DEC Network Systems Lab	
Palo Alto, California, USA         	"Ready, Fire, Aim"
<vixie@pa.dec.com> decwrl!vixie
<paul@vix.com>     vixie!paul          alt.pink.bunny.boom.boom.boom moderator
Technical Details
Message-ID: <VIXIE.92May9225910@cognition.pa.dec.com>
Path: arc1-ca.pugleaf.net!wupost!darwin.sura.net!haven.umd.edu!decuac!pa.dec.com!vixie
References: <1992May8.195717.15600@baarsa.bell-atl.com>

Show Full Headers
Complete Article Headers
Newsgroups: comp.unix.bsd,alt.sources
Path: arc1-ca.pugleaf.net!wupost!darwin.sura.net!haven.umd.edu!decuac!pa.dec.com!vixie
From: vixie@pa.dec.com (Paul A Vixie)
Subject: Re: debugging malloc for pyramid
In-Reply-To: dd6kdn0@baarsa.bell-atl.com's message of 8 May 92 19:57:17 GMT
Message-ID: <VIXIE.92May9225910@cognition.pa.dec.com>
Sender: news@PA.dec.com (News)
Organization: DEC Network Software Lab
References: <1992May8.195717.15600@baarsa.bell-atl.com>
Date: 9 May 92 22:59:10
Lines: 408