home *** CD-ROM | disk | FTP | other *** search
- From mipos3!intelca!oliveb!ames!husc6!linus!necntc!ncoast!allbery Mon Sep 19 12:23:28 PDT 1988
- Article 535 of comp.sources.misc:
- Path: td2cad!mipos3!intelca!oliveb!ames!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
-
-
-