home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume04 / smap < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  12.2 KB

  1. From mipos3!intelca!oliveb!ames!husc6!linus!necntc!ncoast!allbery Mon Sep 19 12:23:28 PDT 1988
  2. Article 535 of comp.sources.misc:
  3. Path: td2cad!mipos3!intelca!oliveb!ames!husc6!linus!necntc!ncoast!allbery
  4. From: agc@nixbln.UUCP
  5. Newsgroups: comp.sources.misc
  6. Subject: v04i079: smap -- safe memory allocator package
  7. Message-ID: <8808301808.AA18351@linus.MENET>
  8. Date: 19 Sep 88 01:45:27 GMT
  9. Sender: allbery@ncoast.UUCP
  10. Reply-To: agc@nixbln.UUCP ()
  11. Lines: 449
  12. Approved: allbery@ncoast.UUCP
  13.  
  14. Posting-number: Volume 4, Issue 79
  15. Submitted-by: "A. Nonymous" <agc@nixbln.UUCP>
  16. Archive-name: smap
  17.  
  18. ["careware"?!  ++bsa]
  19.  
  20. Please find enclosed a package which I have called smap, for "Safe
  21. Memory Allocator Package". It acts as a wrapper around malloc, calloc,
  22. realloc and free to check that they behave themselves. The only thing I
  23. am not happy with is the name, so change it if you want. I have made
  24. this package into what I call "careware" - if people find it useful,
  25. I suggest that they send what they think it's worth to a charity of
  26. their choice.
  27.  
  28. Regards,
  29. Alistair G. Crooks (...!uunet!linus!nixbur!nixpbe!nixbln!agc)
  30.  
  31. #!/bin/sh
  32. # to extract, remove the header and type "sh filename"
  33. if `test ! -s ./README`
  34. then
  35. echo "writing ./README"
  36. cat > ./README << '\Rogue\Monster\'
  37. smap - a safe memory allocator package.
  38.  
  39. This package acts as a buffer around any calls to malloc, calloc, realloc
  40. and free, checking that everything takes place in an orderly manner. It is
  41. intended that this package should be used in the debug phase of a project.
  42. There are two main files contained herein -
  43.  
  44. smap.h    should be included in EVERY source file that calls any of malloc,
  45.     calloc, realloc, or free. It should be included before the calls
  46.     of these functions. It redefines the allocation and freeing routines
  47.     to those included in the file smap.c
  48.  
  49. smap.c    contains "replacements", or outer shells, for malloc, calloc, realloc
  50.     and free, and defines three new functions called _blkstart(),
  51.     _blkend(), and _blkignore(). These functions introduce a new concept
  52.     of a program allocation block. Each block is delimited by a
  53.     _blkstart() and a _blkend(). When _blkend() is called, all memory
  54.     that has been allocated since the last call of _blkstart() will be
  55.     checked to see that it has been subsequently freed. Any memory
  56.     purposely left allocated can be marked as such by calling
  57.     _blkignore(ptr), where ptr is the pointer to the memory that was
  58.     allocated. Allocation blocks can be nested.
  59.  
  60. Possible errors which will be picked up are:
  61.  
  62. _malloc: run out of slots    * Re-compile smap.c with a larger MAXSLOTS *
  63. _calloc: run out of slots    * Re-compile smap.c with a larger MAXSLOTS *
  64. _realloc: realloc not previously malloc'd
  65. _free: free not previously malloc'd
  66. _free: free after previous freeing
  67.  
  68. Each of these errors, when encountered, will send the appropriate error
  69. message to the standard error stream, and then send a SIGQUIT signal to
  70. itself, thereby generating a core dump, for future information via a
  71. debugger.
  72.  
  73. Possible warnings which will be picked up are:
  74.  
  75. _malloc: unusual size %d bytes
  76. _malloc: unable to malloc %d bytes
  77. _malloc: malloc returned a non-freed pointer
  78. _calloc: unusual size %d bytes
  79. _calloc: unable to malloc %d bytes
  80. _calloc: malloc returned a non-freed pointer
  81. _realloc: realloc failure %d bytes
  82. _realloc: realloc after previous freeing
  83. _blkend: %d bytes unfreed
  84. _blkignore: pointer has not been allocated
  85.  
  86. Upon detection of a warning condition, the appropriate error message will
  87. be sent to the standard error stream, and execution will continue.
  88.  
  89. To install the package:
  90.  
  91. 1. Place the file smap.h in a directory where it can be found by the
  92.    compiler, if necessary adding the directory name to the list of
  93.    include directories given to the compiler.
  94.  
  95. 2. Place a C pre-processor call to '#include "smap.h"' in EVERY source
  96.    file which calls any of malloc, calloc, realloc or free. This must be
  97.    done BEFORE any calls to any of these functions. If either of these
  98.    two conditions is not fulfilled, spurious errors will occur with this
  99.    software, usually in the _free function.
  100.  
  101. 3. Compile the file smap.c.
  102.  
  103. 4. Re-compile all source files that have changed, and link your object
  104.    files with the file smap.o.
  105.  
  106. 5. Run the program, and investigate any core dumps which occur.
  107.  
  108. .....
  109.  
  110. 6. When memory allocation bugs have been found, the package can be disabled
  111.    by defining the preprocessor flag NOMEMCHECK, and recompiling all source
  112.    modules that have included "smap.h". Note that the _blk*() routines will
  113.    cease to work when you do this.
  114.  
  115. This package was originally developed to locate instances of freeing
  116. memory twice, which was causing unusual core dumps in places not related
  117. to the problem. This package is intended to locate these bugs when they
  118. happen. I have used it both at home and at work, finding it very useful
  119. in my own work, and almost invaluable when integrating my work with other
  120. pieces, especially when written by other people.
  121.  
  122. I have designated it "careware". If you find it useful, I suggest that you
  123. send what you think it is worth to a charity of your choice. I would also like
  124. you to give this package any distribution that you think it deserves.
  125.  
  126. Alistair G. Crooks,
  127. Joypace Ltd., 2 Vale Road, Hawkhurst, Kent TN18 4BU, UK. (+44 5805 3114)
  128. UUCP Europe:                   ...!mcvax!unido!nixpbe!nixbln!agc   
  129. UUCP the rest of the world:    ...!uunet!linus!nixbur!nixpbe!nixbln!agc
  130. \Rogue\Monster\
  131. else
  132.   echo "will not over write ./README"
  133. fi
  134. if `test ! -s ./Makefile`
  135. then
  136. echo "writing ./Makefile"
  137. cat > ./Makefile << '\Rogue\Monster\'
  138. CFLAGS = -gx
  139. CC = mcc
  140. OBJ = smap.o
  141. SRC = smap.c
  142. INC = smap.h
  143.  
  144. all : ${OBJ} tst
  145.  
  146. ${OBJ} : ${INC} ${SRC}
  147.     ${CC} ${CFLAGS} -c ${SRC}
  148.  
  149. tst : tst.c ${INC} ${OBJ}
  150.     ${CC} ${CFLAGS} tst.c ${OBJ} -o tst
  151.  
  152. \Rogue\Monster\
  153. else
  154.   echo "will not over write ./Makefile"
  155. fi
  156. if `test ! -s ./smap.c`
  157. then
  158. echo "writing ./smap.c"
  159. cat > ./smap.c << '\Rogue\Monster\'
  160. /*
  161.  *    @(#)smap.c    1.2    30/08/88    16:28:19    agc
  162.  *
  163.  *    Copyright 1988, Joypace Ltd., UK. This product is "careware".
  164.  *    If you find it useful, I suggest that you send what you think
  165.  *    it is worth to the charity of your choice.
  166.  *
  167.  *    Alistair G. Crooks,                +44 5805 3114
  168.  *    Joypace Ltd.,
  169.  *    2 Vale Road,
  170.  *    Hawkhurst,
  171.  *    Kent TN18 4BU,
  172.  *    UK.
  173.  *
  174.  *    UUCP Europe                 ...!mcvax!unido!nixpbe!nixbln!agc
  175.  *    UUCP everywhere else ...!uunet!linus!nixbur!nixpbe!nixbln!agc
  176.  *
  177.  *    smap.c - source file for debugging aids.
  178.  */
  179. #ifndef lint
  180. char    *nsccsid = "@(#)smap.c    1.2 30/08/88 16:28:19    agc";
  181. #endif /* lint */
  182.  
  183. #include <stdio.h>
  184. #include <signal.h>
  185.  
  186. typedef struct _slotstr {
  187.     char        *s_ptr;        /* the allocated area */
  188.     unsigned int    s_size;        /* its size */
  189.     char        s_freed;    /* whether it's been freed yet */
  190.     char        s_blkno;    /* program block reference number */
  191. } SLOT;
  192.  
  193. #ifndef MAXSLOTS
  194. #define MAXSLOTS    4096
  195. #endif /* MAXSLOTS */
  196.  
  197. static SLOT    slots[MAXSLOTS];
  198. static int    slotc;
  199. static int    blkno;
  200.  
  201. #define WARNING(s1, s2)        (void) fprintf(stderr, s1, s2)
  202.  
  203. extern char    *malloc();
  204. extern char    *calloc();
  205. extern char    *realloc();
  206.  
  207.  
  208. /*
  209.  *    abort - print a warning on stderr, and send a SIGQUIT to ourself
  210.  */
  211. static void
  212. abort(s1, s2)
  213. char    *s1;
  214. char    *s2;
  215. {
  216.     WARNING(s1, s2);
  217.     (void) kill(getpid(), SIGQUIT);    /* core dump here */
  218. }
  219.  
  220.  
  221. /*
  222.  *    _malloc - wrapper around malloc. Warns if unusual size given, or the
  223.  *    real malloc returns a NULL pointer. Returns a pointer to the
  224.  *    malloc'd area
  225.  */
  226. char *
  227. _malloc(size)
  228. unsigned int    size;
  229. {
  230.     SLOT    *sp;
  231.     char    *ptr;
  232.     int    i;
  233.  
  234.     if (size == 0)
  235.         WARNING("_malloc: unusual size %d bytes\n", size);
  236.     if ((ptr = (char *) malloc(size)) == (char *) NULL)
  237.         WARNING("_malloc: unable to malloc %d bytes\n", size);
  238.     for (i = 0, sp = slots ; i < slotc ; i++, sp++)
  239.         if (sp->s_ptr == ptr)
  240.             break;
  241.     if (i == slotc) {
  242.         if (slotc == MAXSLOTS - 1)
  243.             abort("_malloc: run out of slots\n", (char *) NULL);
  244.         sp = &slots[slotc++];
  245.     } else if (!sp->s_freed)
  246.         WARNING("_malloc: malloc returned a non-freed pointer\n", NULL);
  247.     sp->s_size = size;
  248.     sp->s_freed = 0;
  249.     sp->s_ptr = ptr;
  250.     sp->s_blkno = blkno;
  251.     return(sp->s_ptr);
  252. }
  253.  
  254.  
  255. /*
  256.  *    _calloc - wrapper for calloc. Calls _malloc to allocate the area, and
  257.  *    then sets the contents of the area to NUL bytes. Returns its address.
  258.  */
  259. char *
  260. _calloc(nel, size)
  261. int        nel;
  262. unsigned int    size;
  263. {
  264.     unsigned int    tot;
  265.     char        *ptr;
  266.     char        *cp;
  267.  
  268.     tot = nel * size;
  269.     ptr = _malloc(tot);
  270.     if ((cp = ptr) == (char *) NULL)
  271.         return((char *) NULL);
  272.     while (tot--)
  273.         *cp++ = 0;
  274.     return(ptr);
  275. }
  276.  
  277.  
  278. /*
  279.  *    _realloc - wrapper for realloc. Checks area already alloc'd and
  280.  *    not freed. Returns its address
  281.  */
  282. char *
  283. _realloc(ptr, size)
  284. char        *ptr;
  285. unsigned int    size;
  286. {
  287.     SLOT    *sp;
  288.     int    i;
  289.  
  290.     for (i = 0, sp = slots ; i < slotc ; i++, sp++)
  291.         if (sp->s_ptr == ptr)
  292.             break;
  293.     if (i == slotc)
  294.         abort("_realloc: realloc on unallocated area\n", (char *) NULL);
  295.     if (sp->s_freed)
  296.         WARNING("_realloc: realloc on freed area\n", (char *) NULL);
  297.     if ((sp->s_ptr = (char *) realloc(ptr, size)) == (char *) NULL)
  298.         WARNING("_realloc: realloc failure %d bytes\n", size);
  299.     sp->s_size = size;
  300.     sp->s_blkno = blkno;
  301.     return(sp->s_ptr);
  302. }
  303.  
  304.  
  305. /*
  306.  *    _free - wrapper for free. Loop through allocated slots, until you
  307.  *    find the one corresponding to pointer. If none, then it's an attempt
  308.  *    to free an unallocated area. If it's already freed, then tell user.
  309.  */
  310. void
  311. _free(ptr)
  312. char    *ptr;
  313. {
  314.     SLOT    *sp;
  315.     int    i;
  316.  
  317.     for (i = 0, sp = slots ; i < slotc ; i++, sp++)
  318.         if (sp->s_ptr == ptr)
  319.             break;
  320.     if (i == slotc)
  321.         abort("_free: free not previously malloc'd\n", (char *) NULL);
  322.     if (sp->s_freed)
  323.         abort("_free: free after previous freeing\n", (char *) NULL);
  324.     (void) free(sp->s_ptr);
  325.     sp->s_freed = 1;
  326. }
  327.  
  328.  
  329. /*
  330.  *    _blkstart - start of a program block. Increase the block reference
  331.  *    number by one.
  332.  */
  333. void
  334. _blkstart()
  335. {
  336.     blkno += 1;
  337. }
  338.  
  339.  
  340. /*
  341.  *    _blkend - end of a program block. Check all areas allocated in this
  342.  *    block have been freed. Decrease the block number by one.
  343.  */
  344. void
  345. _blkend()
  346. {
  347.     SLOT    *sp;
  348.     int    i;
  349.  
  350.     if (blkno == 0) {
  351.         WARNING("_blkend: unmatched call to _blkend\n", NULL);
  352.         return;
  353.     }
  354.     for (i = 0, sp = slots ; i < slotc ; i++, sp++)
  355.         if (sp->s_blkno == blkno && !sp->s_freed)
  356.             WARNING("_blkend: %d bytes unfreed\n", sp->s_size);
  357.     blkno -= 1;
  358. }
  359.  
  360.  
  361. /*
  362.  *    _blkignore - find the slot corresponding to ptr, and set its block
  363.  *    number to zero, to avoid _blkend picking it up when checking.
  364.  */
  365. void
  366. _blkignore(ptr)
  367. char    *ptr;
  368. {
  369.     SLOT    *sp;
  370.     int    i;
  371.  
  372.     for (i = 0, sp = slots ; i < slotc ; i++, sp++)
  373.         if (sp->s_ptr == ptr)
  374.             break;
  375.     if (i == slotc)
  376.         WARNING("_blkignore: pointer has not been allocated\n", NULL);
  377.     else
  378.         sp->s_blkno = 0;
  379. }
  380. \Rogue\Monster\
  381. else
  382.   echo "will not over write ./smap.c"
  383. fi
  384. if `test ! -s ./smap.h`
  385. then
  386. echo "writing ./smap.h"
  387. cat > ./smap.h << '\Rogue\Monster\'
  388. /*
  389.  *    @(#)smap.h    1.1    30/08/88    16:07:36    agc
  390.  *
  391.  *    Copyright 1988, Joypace Ltd., UK. This product is "careware".
  392.  *    If you find it useful, I suggest that you send what you think
  393.  *    it is worth to the charity of your choice.
  394.  *
  395.  *    Alistair G. Crooks,                +44 5805 3114
  396.  *    Joypace Ltd.,
  397.  *    2 Vale Road,
  398.  *    Hawkhurst,
  399.  *    Kent TN18 4BU,
  400.  *    UK.
  401.  *
  402.  *    UUCP Europe                 ...!mcvax!unido!nixpbe!nixbln!agc
  403.  *    UUCP everywhere else ...!uunet!linus!nixbur!nixpbe!nixbln!agc
  404.  *
  405.  *    smap.h - include file for debugging aids. This file must be included,
  406.  *    before any calls, in any source file that calls malloc, calloc,
  407.  *    realloc, or free. (Note alloca is not included in this list).
  408.  */
  409. #ifdef NOMEMCHECK
  410. #define    _blkstart()
  411. #define _blkend()
  412. #define _blkignore(p)
  413. #else /* not NOMEMCHECK */
  414. #ifndef malloc
  415. #define malloc    _malloc
  416. #define calloc    _calloc
  417. #define realloc    _realloc
  418. #define free    _free
  419. #endif /* not malloc */
  420. extern void    _blkstart();
  421. extern void    _blkend();
  422. extern void    _blkignore();
  423. #endif /* not NOMEMCHECK */
  424. \Rogue\Monster\
  425. else
  426.   echo "will not over write ./smap.h"
  427. fi
  428. if `test ! -s ./tst.c`
  429. then
  430. echo "writing ./tst.c"
  431. cat > ./tst.c << '\Rogue\Monster\'
  432. #include <stdio.h>
  433. #include "smap.h"
  434.  
  435. main()
  436. {
  437.     char    *ptr;
  438.     char    *ign;
  439.  
  440.     _blkstart();
  441.     _blkstart();
  442.     if ((ptr = (char *) malloc(10)) == (char *) NULL)
  443.         (void) fprintf(stderr, "malloc failure\n");
  444.     (void) free(ptr);
  445.     _blkend();
  446.     if ((ptr = (char *) malloc(10)) == (char *) NULL)
  447.         (void) fprintf(stderr, "malloc failure\n");
  448.     if ((ign = (char *) malloc(20)) == (char *) NULL)
  449.         (void) fprintf(stderr, "malloc failure\n");
  450.     _blkignore(ign);
  451.     (void) free(ptr);
  452.     _blkend();
  453.     _blkend();
  454.     (void) free(ptr);
  455. }
  456.  
  457. \Rogue\Monster\
  458. else
  459.   echo "will not over write ./tst.c"
  460. fi
  461. echo "Finished archive 1 of 1"
  462. exit
  463.  
  464.  
  465.