home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.unix
- From: pefv700@hermes.chpc.utexas.edu (Christopher Phillips)
- Subject: v27i066: leak - quick and dirty code to find memory leaks, Part01/01
- Message-id: <1.750376543.23906@gw.home.vix.com>
- Sender: unix-sources-moderator@gw.home.vix.com
- Approved: vixie@gw.home.vix.com
-
- Submitted-By: pefv700@hermes.chpc.utexas.edu (Christopher Phillips)
- Posting-Number: Volume 27, Issue 66
- Archive-Name: leak/part01
-
- What leak does:
-
- * Logs all malloc/realloc/free calls to dbm files
- with filename and line number
- * Complains about reallocing/freeing addresses not
- the result of a prior malloc/realloc
- * Dumps unfreed addresses upon request
-
- How to use leak:
-
- * #include "leak.h" in all source files that call
- malloc/realloc/free
- * recompile
- * run program
- * run leakdump
-
- pefv700@hermes.chpc.utexas.edu (Christopher Phillips)
-
- #! /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: leak leak/Makefile leak/README leak/leak.c leak/leak.h
- # leak/leakdump.c leak/leaktest.c
- # Wrapped by pefv700@hermes on Mon Oct 11 11:39:31 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test ! -d 'leak' ; then
- echo shar: Creating directory \"'leak'\"
- mkdir 'leak'
- fi
- if test -f 'leak/Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'leak/Makefile'\"
- else
- echo shar: Extracting \"'leak/Makefile'\" \(293 characters\)
- sed "s/^X//" >'leak/Makefile' <<'END_OF_FILE'
- Xall: test leaktest leakdump
- X
- Xleaktest: leaktest.o leak.o
- X $(CC) -o $@ leaktest.o leak.o
- X
- Xleakdump: leakdump.o leak.o
- X $(CC) -o $@ leakdump.o leak.o
- X
- Xtest: leaktest leakdump
- X @echo Running leaktest
- X @leaktest
- X @echo Running leakdump
- X @leakdump
- X
- Xclean:
- X -rm -f *.o leaktest leakdump *.dir *.pag
- END_OF_FILE
- if test 293 -ne `wc -c <'leak/Makefile'`; then
- echo shar: \"'leak/Makefile'\" unpacked with wrong size!
- fi
- # end of 'leak/Makefile'
- fi
- if test -f 'leak/README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'leak/README'\"
- else
- echo shar: Extracting \"'leak/README'\" \(1545 characters\)
- sed "s/^X//" >'leak/README' <<'END_OF_FILE'
- X
- XLEAK - Quick and dirty code to find memory leaks
- X (Requires ANSI C and ndbm)
- X
- XWhat leak does:
- X
- X * Logs all malloc/realloc/free calls to dbm files
- X with filename and line number
- X * Complains about reallocing/freeing addresses not
- X the result of a prior malloc/realloc
- X * Dumps unfreed addresses upon request
- X
- XHow to use leak:
- X
- X * #include "leak.h" in all source files that call
- X malloc/realloc/free
- X * recompile
- X * run program
- X * run leakdump
- X
- XThat's all there is to it. For example:
- X
- X% make
- Xcc -c leaktest.c -o leaktest.o
- Xcc -c leak.c -o leak.o
- Xcc -o leaktest leaktest.o leak.o
- Xcc -c leakdump.c -o leakdump.o
- Xcc -o leakdump leakdump.o leak.o
- X% leaktest
- X% leakdump
- XNonfreed blocks:
- XAddress Size Line File
- X------------------------------------
- X140004110 40 16 leaktest.c
- X%
- X
- XNotes:
- X * The dbm files are not automatically deleted
- X * When using libraries that use malloc/realloc/free
- X but for which you don't have source, don't have leak
- X log the use of this memory. For example, if libMRF.a
- X mallocs memory that you should free, don't have leak
- X log the free or it will complain.
- X * If you have library functions whose main function
- X is to call malloc/realloc, it is usually more relevant
- X to know which function called the library function.
- X Unfortunately, determining that information is
- X platform-specific.
- X * All malloced/realloced memory should be explicitly
- X freed or it will show up in the dump.
- X
- X
- XChris
- X
- X-----------------------
- XChristopher G. Phillips
- Xpefv700@utpe.pe.utexas.edu
- END_OF_FILE
- if test 1545 -ne `wc -c <'leak/README'`; then
- echo shar: \"'leak/README'\" unpacked with wrong size!
- fi
- # end of 'leak/README'
- fi
- if test -f 'leak/leak.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'leak/leak.c'\"
- else
- echo shar: Extracting \"'leak/leak.c'\" \(3949 characters\)
- sed "s/^X//" >'leak/leak.c' <<'END_OF_FILE'
- X/*
- X * Author: Christopher G. Phillips
- X * Copyright (C) 1993 All Rights Reserved
- X *
- X * NOTICE
- X *
- X * Permission to use, copy, modify, and distribute this software and
- X * its documentation for any purpose and without fee is hereby granted
- X * provided that the above copyright notice appear in all copies and
- X * that both the copyright notice and this permission notice appear in
- X * supporting documentation.
- X *
- X * The author makes no representations about the suitability of this
- X * software for any purpose. This software is provided ``as is''
- X * without express or implied warranty.
- X */
- X
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <string.h>
- X#include <unistd.h>
- X#include <fcntl.h>
- X#include "leak.h"
- X
- X#define FILE_DBMFILENAME "filedbm"
- X#define MEMORY_DBMFILENAME "memdbm"
- X
- Xvoid *_ptr;
- X
- Xtypedef char *DPTR;
- X
- Xstatic DBM *filedbm = NULL;
- Xstatic DBM *memdbm = NULL;
- Xstatic int nextfile = -1;
- X
- Xstruct memdata {
- X size_t size;
- X int file;
- X int line;
- X};
- X
- Xstatic void
- Xopendbmfiles(mode_t mode)
- X{
- X if (filedbm == NULL && (filedbm = dbm_open(FILE_DBMFILENAME, mode,
- X S_IRUSR | S_IWUSR)) == NULL
- X || memdbm == NULL && (memdbm = dbm_open(MEMORY_DBMFILENAME, mode,
- X S_IRUSR | S_IWUSR)) == NULL) {
- X perror("dbm_open");
- X exit(1);
- X }
- X}
- X
- Xstatic int
- Xfile2int(const char *file)
- X{
- X datum key, data;
- X
- X key.dptr = (DPTR)file;
- X key.dsize = strlen(file) + 1;
- X data = dbm_fetch(filedbm, key);
- X if (data.dptr) {
- X int i;
- X
- X (void)memcpy(&i, data.dptr, sizeof i);
- X return i;
- X } else {
- X ++nextfile;
- X data.dptr = (DPTR)&nextfile;
- X data.dsize = sizeof nextfile;
- X if (dbm_store(filedbm, key, data, DBM_INSERT) < 0) {
- X perror("dbm_store");
- X exit(1);
- X }
- X return nextfile;
- X }
- X}
- X
- Xstatic char *
- Xint2file(int file)
- X{
- X datum key, data;
- X int i;
- X
- X for (key = dbm_firstkey(filedbm); key.dptr;
- X key = dbm_nextkey(filedbm)) {
- X data = dbm_fetch(filedbm, key);
- X if (data.dptr == NULL) {
- X perror("dbm_fetch");
- X continue;
- X }
- X (void)memcpy(&i, data.dptr, sizeof i);
- X if (i == file)
- X return key.dptr;
- X }
- X return "???";
- X}
- X
- Xvoid
- X_dbinsert(void *p, size_t size, const char *file, int line, int mode)
- X{
- X struct memdata md;
- X datum key, data;
- X
- X if (!filedbm || !memdbm)
- X opendbmfiles(O_RDWR | O_CREAT | O_TRUNC);
- X
- X md.file = file2int(file);
- X
- X md.size = size;
- X md.line = line;
- X key.dptr = (DPTR)&p;
- X key.dsize = sizeof p;
- X data.dptr = (DPTR)&md;
- X data.dsize = sizeof md;
- X
- X if (dbm_store(memdbm, key, data, DBM_INSERT) == -1) {
- X perror("dbm_store");
- X exit(1);
- X }
- X}
- X
- Xvoid
- X_dbdelete(void *p, const char *file, int line)
- X{
- X struct memdata md;
- X datum key, data;
- X
- X key.dptr = (DPTR)&p;
- X key.dsize = sizeof p;
- X
- X if (memdbm == NULL) {
- X fprintf(stderr, "free before malloc from \"%s\", line %d\n",
- X file, line);
- X exit(1);
- X } else if (dbm_delete(memdbm, key) == -1) {
- X fprintf(stderr,
- X "free unmalloced pointer %p from \"%s\", line %d\n", p, file,
- X line);
- X exit(1);
- X }
- X}
- X
- Xvoid
- X_dbdump(mode_t mode)
- X{
- X struct memdata *mdp;
- X datum key, data;
- X int do_title = 1;
- X
- X if (!filedbm || !memdbm)
- X opendbmfiles(mode);
- X
- X for (key = dbm_firstkey(memdbm); key.dptr; key = dbm_nextkey(memdbm)) {
- X data = dbm_fetch(memdbm, key);
- X if (data.dptr == NULL) {
- X perror("dbm_fetch");
- X continue;
- X }
- X if (do_title) {
- X int i;
- X
- X printf("Nonfreed blocks:\n");
- X printf("Address \tSize\tLine\tFile\n");
- X for (i = 0; i < 36; i++)
- X putchar('-');
- X putchar('\n');
- X do_title = 0;
- X }
- X mdp = (struct memdata *)data.dptr;
- X#ifndef sun
- X printf("%08p\t%d\t%d\t%s\n", *(void **)key.dptr,
- X#else
- X printf("%08x\t%d\t%d\t%s\n", (int)*(void **)key.dptr,
- X#endif
- X mdp->size, mdp->line, int2file(mdp->file));
- X }
- X}
- X
- X#if 0
- Xvoid
- Xexit(int status)
- X{
- X _dbdump(O_RDONLY);
- X (void)dbm_close(memdbm);
- X (void)dbm_close(filedbm);
- X (void)remove("memdbm.dir");
- X (void)remove("memdbm.pag");
- X (void)remove("filedbm.dir");
- X (void)remove("filedbm.pag");
- X fflush(NULL);
- X _exit(status);
- X}
- X#endif
- END_OF_FILE
- if test 3949 -ne `wc -c <'leak/leak.c'`; then
- echo shar: \"'leak/leak.c'\" unpacked with wrong size!
- fi
- # end of 'leak/leak.c'
- fi
- if test -f 'leak/leak.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'leak/leak.h'\"
- else
- echo shar: Extracting \"'leak/leak.h'\" \(1343 characters\)
- sed "s/^X//" >'leak/leak.h' <<'END_OF_FILE'
- X/*
- X * Author: Christopher G. Phillips
- X * Copyright (C) 1993 All Rights Reserved
- X *
- X * NOTICE
- X *
- X * Permission to use, copy, modify, and distribute this software and
- X * its documentation for any purpose and without fee is hereby granted
- X * provided that the above copyright notice appear in all copies and
- X * that both the copyright notice and this permission notice appear in
- X * supporting documentation.
- X *
- X * The author makes no representations about the suitability of this
- X * software for any purpose. This software is provided ``as is''
- X * without express or implied warranty.
- X */
- X
- X#ifndef H_LEAK
- X#define H_LEAK
- X
- X#include <sys/types.h>
- X#include <stdlib.h>
- X#include <ndbm.h>
- X
- Xextern void *_ptr;
- Xextern void _dbinsert(void *, size_t, const char *, int, int);
- Xextern void _dbdelete(void *, const char *, int);
- X
- X#define malloc(s) \
- X (_ptr = malloc(s), _dbinsert(_ptr, s, __FILE__, __LINE__, DBM_INSERT), _ptr)
- X
- X#define realloc(p, s) \
- X ((_ptr = realloc(p, s)), \
- X ((_ptr && _ptr == p) \
- X ? _dbinsert(_ptr, s, __FILE__, __LINE__, DBM_REPLACE), 0 : 0), \
- X (_ptr ? \
- X (p ? _dbdelete(p, __FILE__, __LINE__), 0 : 0), \
- X _dbinsert(_ptr, s, __FILE__, __LINE__, DBM_INSERT), 0 : 0), \
- X _ptr)
- X
- X#define free(p) (p ? _dbdelete(p, __FILE__, __LINE__), 0 : 0), free(p)
- X
- X#endif /* H_LEAK */
- END_OF_FILE
- if test 1343 -ne `wc -c <'leak/leak.h'`; then
- echo shar: \"'leak/leak.h'\" unpacked with wrong size!
- fi
- # end of 'leak/leak.h'
- fi
- if test -f 'leak/leakdump.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'leak/leakdump.c'\"
- else
- echo shar: Extracting \"'leak/leakdump.c'\" \(774 characters\)
- sed "s/^X//" >'leak/leakdump.c' <<'END_OF_FILE'
- X/*
- X * Author: Christopher G. Phillips
- X * Copyright (C) 1993 All Rights Reserved
- X *
- X * NOTICE
- X *
- X * Permission to use, copy, modify, and distribute this software and
- X * its documentation for any purpose and without fee is hereby granted
- X * provided that the above copyright notice appear in all copies and
- X * that both the copyright notice and this permission notice appear in
- X * supporting documentation.
- X *
- X * The author makes no representations about the suitability of this
- X * software for any purpose. This software is provided ``as is''
- X * without express or implied warranty.
- X */
- X
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <fcntl.h>
- X#include "leak.h"
- X
- Xint
- Xmain(void)
- X{
- X _dbdump(O_RDONLY);
- X
- X exit(0);
- X}
- END_OF_FILE
- if test 774 -ne `wc -c <'leak/leakdump.c'`; then
- echo shar: \"'leak/leakdump.c'\" unpacked with wrong size!
- fi
- # end of 'leak/leakdump.c'
- fi
- if test -f 'leak/leaktest.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'leak/leaktest.c'\"
- else
- echo shar: Extracting \"'leak/leaktest.c'\" \(237 characters\)
- sed "s/^X//" >'leak/leaktest.c' <<'END_OF_FILE'
- X#include <stdio.h>
- X#include <stdlib.h>
- X#include <limits.h>
- X#include "leak.h"
- X
- Xint
- Xmain(void)
- X{
- X void *p, *q;
- X
- X p = malloc(3);
- X free(NULL);
- X if ((q = realloc(p, INT_MAX)) == NULL)
- X free(p);
- X else
- X free(q);
- X p = malloc(40);
- X
- X exit(0);
- X}
- END_OF_FILE
- if test 237 -ne `wc -c <'leak/leaktest.c'`; then
- echo shar: \"'leak/leaktest.c'\" unpacked with wrong size!
- fi
- # end of 'leak/leaktest.c'
- fi
- echo shar: End of shell archive.
- exit 0
-