home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume4
/
smap
< prev
next >
Wrap
Text File
|
1989-02-03
|
12KB
|
461 lines
Path: xanth!mcnc!rutgers!mailrus!husc6!linus!necntc!ncoast!allbery
From: agc@nixbln.UUCP
Newsgroups: comp.sources.misc
Subject: v04i079: smap -- safe memory allocator package
Message-ID: <8808301808.AA18351@linus.MENET>
Date: 19 Sep 88 01:45:27 GMT
Sender: allbery@ncoast.UUCP
Reply-To: agc@nixbln.UUCP ()
Lines: 449
Approved: allbery@ncoast.UUCP
Posting-number: Volume 4, Issue 79
Submitted-by: "A. Nonymous" <agc@nixbln.UUCP>
Archive-name: smap
["careware"?! ++bsa]
Please find enclosed a package which I have called smap, for "Safe
Memory Allocator Package". It acts as a wrapper around malloc, calloc,
realloc and free to check that they behave themselves. The only thing I
am not happy with is the name, so change it if you want. I have made
this package into what I call "careware" - if people find it useful,
I suggest that they send what they think it's worth to a charity of
their choice.
Regards,
Alistair G. Crooks (...!uunet!linus!nixbur!nixpbe!nixbln!agc)
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\Rogue\Monster\'
smap - a safe memory allocator package.
This package acts as a buffer around any calls to malloc, calloc, realloc
and free, checking that everything takes place in an orderly manner. It is
intended that this package should be used in the debug phase of a project.
There are two main files contained herein -
smap.h should be included in EVERY source file that calls any of malloc,
calloc, realloc, or free. It should be included before the calls
of these functions. It redefines the allocation and freeing routines
to those included in the file smap.c
smap.c contains "replacements", or outer shells, for malloc, calloc, realloc
and free, and defines three new functions called _blkstart(),
_blkend(), and _blkignore(). These functions introduce a new concept
of a program allocation block. Each block is delimited by a
_blkstart() and a _blkend(). When _blkend() is called, all memory
that has been allocated since the last call of _blkstart() will be
checked to see that it has been subsequently freed. Any memory
purposely left allocated can be marked as such by calling
_blkignore(ptr), where ptr is the pointer to the memory that was
allocated. Allocation blocks can be nested.
Possible errors which will be picked up are:
_malloc: run out of slots * Re-compile smap.c with a larger MAXSLOTS *
_calloc: run out of slots * Re-compile smap.c with a larger MAXSLOTS *
_realloc: realloc not previously malloc'd
_free: free not previously malloc'd
_free: free after previous freeing
Each of these errors, when encountered, will send the appropriate error
message to the standard error stream, and then send a SIGQUIT signal to
itself, thereby generating a core dump, for future information via a
debugger.
Possible warnings which will be picked up are:
_malloc: unusual size %d bytes
_malloc: unable to malloc %d bytes
_malloc: malloc returned a non-freed pointer
_calloc: unusual size %d bytes
_calloc: unable to malloc %d bytes
_calloc: malloc returned a non-freed pointer
_realloc: realloc failure %d bytes
_realloc: realloc after previous freeing
_blkend: %d bytes unfreed
_blkignore: pointer has not been allocated
Upon detection of a warning condition, the appropriate error message will
be sent to the standard error stream, and execution will continue.
To install the package:
1. Place the file smap.h in a directory where it can be found by the
compiler, if necessary adding the directory name to the list of
include directories given to the compiler.
2. Place a C pre-processor call to '#include "smap.h"' in EVERY source
file which calls any of malloc, calloc, realloc or free. This must be
done BEFORE any calls to any of these functions. If either of these
two conditions is not fulfilled, spurious errors will occur with this
software, usually in the _free function.
3. Compile the file smap.c.
4. Re-compile all source files that have changed, and link your object
files with the file smap.o.
5. Run the program, and investigate any core dumps which occur.
.....
6. When memory allocation bugs have been found, the package can be disabled
by defining the preprocessor flag NOMEMCHECK, and recompiling all source
modules that have included "smap.h". Note that the _blk*() routines will
cease to work when you do this.
This package was originally developed to locate instances of freeing
memory twice, which was causing unusual core dumps in places not related
to the problem. This package is intended to locate these bugs when they
happen. I have used it both at home and at work, finding it very useful
in my own work, and almost invaluable when integrating my work with other
pieces, especially when written by other people.
I have designated it "careware". If you find it useful, I suggest that you
send what you think it is worth to a charity of your choice. I would also like
you to give this package any distribution that you think it deserves.
Alistair G. Crooks,
Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 5805 3114)
UUCP Europe: ...!mcvax!unido!nixpbe!nixbln!agc
UUCP the rest of the world: ...!uunet!linus!nixbur!nixpbe!nixbln!agc
\Rogue\Monster\
else
echo "will not over write ./README"
fi
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\Rogue\Monster\'
CFLAGS = -gx
CC = mcc
OBJ = smap.o
SRC = smap.c
INC = smap.h
all : ${OBJ} tst
${OBJ} : ${INC} ${SRC}
${CC} ${CFLAGS} -c ${SRC}
tst : tst.c ${INC} ${OBJ}
${CC} ${CFLAGS} tst.c ${OBJ} -o tst
\Rogue\Monster\
else
echo "will not over write ./Makefile"
fi
if `test ! -s ./smap.c`
then
echo "writing ./smap.c"
cat > ./smap.c << '\Rogue\Monster\'
/*
* @(#)smap.c 1.2 30/08/88 16:28:19 agc
*
* Copyright 1988, Joypace Ltd., UK. This product is "careware".
* If you find it useful, I suggest that you send what you think
* it is worth to the charity of your choice.
*
* Alistair G. Crooks, +44 5805 3114
* Joypace Ltd.,
* 2 Vale Road,
* Hawkhurst,
* Kent TN18 4BU,
* UK.
*
* UUCP Europe ...!mcvax!unido!nixpbe!nixbln!agc
* UUCP everywhere else ...!uunet!linus!nixbur!nixpbe!nixbln!agc
*
* smap.c - source file for debugging aids.
*/
#ifndef lint
char *nsccsid = "@(#)smap.c 1.2 30/08/88 16:28:19 agc";
#endif /* lint */
#include <stdio.h>
#include <signal.h>
typedef struct _slotstr {
char *s_ptr; /* the allocated area */
unsigned int s_size; /* its size */
char s_freed; /* whether it's been freed yet */
char s_blkno; /* program block reference number */
} SLOT;
#ifndef MAXSLOTS
#define MAXSLOTS 4096
#endif /* MAXSLOTS */
static SLOT slots[MAXSLOTS];
static int slotc;
static int blkno;
#define WARNING(s1, s2) (void) fprintf(stderr, s1, s2)
extern char *malloc();
extern char *calloc();
extern char *realloc();
/*
* abort - print a warning on stderr, and send a SIGQUIT to ourself
*/
static void
abort(s1, s2)
char *s1;
char *s2;
{
WARNING(s1, s2);
(void) kill(getpid(), SIGQUIT); /* core dump here */
}
/*
* _malloc - wrapper around malloc. Warns if unusual size given, or the
* real malloc returns a NULL pointer. Returns a pointer to the
* malloc'd area
*/
char *
_malloc(size)
unsigned int size;
{
SLOT *sp;
char *ptr;
int i;
if (size == 0)
WARNING("_malloc: unusual size %d bytes\n", size);
if ((ptr = (char *) malloc(size)) == (char *) NULL)
WARNING("_malloc: unable to malloc %d bytes\n", size);
for (i = 0, sp = slots ; i < slotc ; i++, sp++)
if (sp->s_ptr == ptr)
break;
if (i == slotc) {
if (slotc == MAXSLOTS - 1)
abort("_malloc: run out of slots\n", (char *) NULL);
sp = &slots[slotc++];
} else if (!sp->s_freed)
WARNING("_malloc: malloc returned a non-freed pointer\n", NULL);
sp->s_size = size;
sp->s_freed = 0;
sp->s_ptr = ptr;
sp->s_blkno = blkno;
return(sp->s_ptr);
}
/*
* _calloc - wrapper for calloc. Calls _malloc to allocate the area, and
* then sets the contents of the area to NUL bytes. Returns its address.
*/
char *
_calloc(nel, size)
int nel;
unsigned int size;
{
unsigned int tot;
char *ptr;
char *cp;
tot = nel * size;
ptr = _malloc(tot);
if ((cp = ptr) == (char *) NULL)
return((char *) NULL);
while (tot--)
*cp++ = 0;
return(ptr);
}
/*
* _realloc - wrapper for realloc. Checks area already alloc'd and
* not freed. Returns its address
*/
char *
_realloc(ptr, size)
char *ptr;
unsigned int size;
{
SLOT *sp;
int i;
for (i = 0, sp = slots ; i < slotc ; i++, sp++)
if (sp->s_ptr == ptr)
break;
if (i == slotc)
abort("_realloc: realloc on unallocated area\n", (char *) NULL);
if (sp->s_freed)
WARNING("_realloc: realloc on freed area\n", (char *) NULL);
if ((sp->s_ptr = (char *) realloc(ptr, size)) == (char *) NULL)
WARNING("_realloc: realloc failure %d bytes\n", size);
sp->s_size = size;
sp->s_blkno = blkno;
return(sp->s_ptr);
}
/*
* _free - wrapper for free. Loop through allocated slots, until you
* find the one corresponding to pointer. If none, then it's an attempt
* to free an unallocated area. If it's already freed, then tell user.
*/
void
_free(ptr)
char *ptr;
{
SLOT *sp;
int i;
for (i = 0, sp = slots ; i < slotc ; i++, sp++)
if (sp->s_ptr == ptr)
break;
if (i == slotc)
abort("_free: free not previously malloc'd\n", (char *) NULL);
if (sp->s_freed)
abort("_free: free after previous freeing\n", (char *) NULL);
(void) free(sp->s_ptr);
sp->s_freed = 1;
}
/*
* _blkstart - start of a program block. Increase the block reference
* number by one.
*/
void
_blkstart()
{
blkno += 1;
}
/*
* _blkend - end of a program block. Check all areas allocated in this
* block have been freed. Decrease the block number by one.
*/
void
_blkend()
{
SLOT *sp;
int i;
if (blkno == 0) {
WARNING("_blkend: unmatched call to _blkend\n", NULL);
return;
}
for (i = 0, sp = slots ; i < slotc ; i++, sp++)
if (sp->s_blkno == blkno && !sp->s_freed)
WARNING("_blkend: %d bytes unfreed\n", sp->s_size);
blkno -= 1;
}
/*
* _blkignore - find the slot corresponding to ptr, and set its block
* number to zero, to avoid _blkend picking it up when checking.
*/
void
_blkignore(ptr)
char *ptr;
{
SLOT *sp;
int i;
for (i = 0, sp = slots ; i < slotc ; i++, sp++)
if (sp->s_ptr == ptr)
break;
if (i == slotc)
WARNING("_blkignore: pointer has not been allocated\n", NULL);
else
sp->s_blkno = 0;
}
\Rogue\Monster\
else
echo "will not over write ./smap.c"
fi
if `test ! -s ./smap.h`
then
echo "writing ./smap.h"
cat > ./smap.h << '\Rogue\Monster\'
/*
* @(#)smap.h 1.1 30/08/88 16:07:36 agc
*
* Copyright 1988, Joypace Ltd., UK. This product is "careware".
* If you find it useful, I suggest that you send what you think
* it is worth to the charity of your choice.
*
* Alistair G. Crooks, +44 5805 3114
* Joypace Ltd.,
* 2 Vale Road,
* Hawkhurst,
* Kent TN18 4BU,
* UK.
*
* UUCP Europe ...!mcvax!unido!nixpbe!nixbln!agc
* UUCP everywhere else ...!uunet!linus!nixbur!nixpbe!nixbln!agc
*
* smap.h - include file for debugging aids. This file must be included,
* before any calls, in any source file that calls malloc, calloc,
* realloc, or free. (Note alloca is not included in this list).
*/
#ifdef NOMEMCHECK
#define _blkstart()
#define _blkend()
#define _blkignore(p)
#else /* not NOMEMCHECK */
#ifndef malloc
#define malloc _malloc
#define calloc _calloc
#define realloc _realloc
#define free _free
#endif /* not malloc */
extern void _blkstart();
extern void _blkend();
extern void _blkignore();
#endif /* not NOMEMCHECK */
\Rogue\Monster\
else
echo "will not over write ./smap.h"
fi
if `test ! -s ./tst.c`
then
echo "writing ./tst.c"
cat > ./tst.c << '\Rogue\Monster\'
#include <stdio.h>
#include "smap.h"
main()
{
char *ptr;
char *ign;
_blkstart();
_blkstart();
if ((ptr = (char *) malloc(10)) == (char *) NULL)
(void) fprintf(stderr, "malloc failure\n");
(void) free(ptr);
_blkend();
if ((ptr = (char *) malloc(10)) == (char *) NULL)
(void) fprintf(stderr, "malloc failure\n");
if ((ign = (char *) malloc(20)) == (char *) NULL)
(void) fprintf(stderr, "malloc failure\n");
_blkignore(ign);
(void) free(ptr);
_blkend();
_blkend();
(void) free(ptr);
}
\Rogue\Monster\
else
echo "will not over write ./tst.c"
fi
echo "Finished archive 1 of 1"
exit