home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume4 / smap < prev    next >
Text File  |  1989-02-03  |  12KB  |  461 lines

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