home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 001-099 / ff027.lzh / SafeMalloc / safemalloc.c next >
C/C++ Source or Header  |  1986-06-29  |  10KB  |  349 lines

  1. /*
  2.  * Article 879 of net.sources:
  3.  * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site unisoft.UUCP
  4.  * Posting-Version: version B 2.10.2 9/18/84; site dataioDataio.UUCP
  5.  * Path: unisoft!lll-lcc!ucdavis!ucbvax!decvax!tektronix!uw-beaver!uw-june!entropy!dataio!bjorn
  6.  * From: bjorn@dataioDataio.UUCP (Bjorn Benson)
  7.  * Newsgroups: net.sources
  8.  * Subject: Solution to "oops, corrupted memory again!"
  9.  * Message-ID: <975@dataioDataio.UUCP>
  10.  * Date: 29 Apr 86 03:04:49 GMT
  11.  * Date-Received: 2 May 86 18:38:02 GMT
  12.  * References: <4495@cbrma.UUCP>
  13.  * Organization: Data I/O Corp., Redmond WA
  14.  * Lines: 268
  15.  * Keywords: malloc free stack tools core memory
  16.  */
  17.  
  18. /*
  19.  * [This posting refers to an article entitled "oops, corrupted memory
  20.  * again!" in net.lang.c.  I am posting it here because it is source.]
  21.  * 
  22.  * My tool for approaching this problem is to build another level of data 
  23.  * abstraction on top of malloc() and free() that implements some checking.  
  24.  * This does a number of things for you:
  25.  *     - Checks for overruns and underruns on allocated data
  26.  *     - Keeps track of where in the program the memory was malloc'ed
  27.  *     - Reports on pieces of memory that were not free'ed
  28.  *     - Records some statistics such as maximum memory used
  29.  *     - Marks newly malloc'ed and newly free'ed memory with special values
  30.  * You can use this scheme to:
  31.  *     - Find bugs such as overrun, underrun, etc because you know where 
  32.  *       a piece of data was malloc'ed and where it was free'ed
  33.  *     - Find bugs where memory was not free'ed
  34.  *     - Find bugs where newly malloc'ed memory is used without initializing
  35.  *     - Find bugs where newly free'ed memory is still used
  36.  *     - Determine how much memory your program really uses
  37.  *     - and other things
  38.  */
  39.  
  40. /*
  41.  * To implement my scheme you must have a C compiler that has __LINE__ and
  42.  * __FILE__ macros.  If your compiler doesn't have these then (a) buy another:
  43.  * compilers that do are available on UNIX 4.2bsd based systems and the PC,
  44.  * and probably on other machines; or (b) change my scheme somehow.  I have
  45.  * recomendations on both these points if you would like them (e-mail please).
  46.  * 
  47.  * There are 3 functions in my package:
  48.  *     char *NEW( uSize )    Allocate memory of uSize bytes
  49.  *                 (equivalent to malloc())
  50.  *     FREE( pPtr )        Free memory allocated by NEW
  51.  *                 (equivalent to free())
  52.  *     TERMINATE()        End system, report errors and stats
  53.  * I personally use two more functions, but have not included them here:
  54.  *     char *STRSAVE( sPtr )    Save a copy of the string in dynamic memory
  55.  *     char *RENEW( pPtr, uSize )
  56.  *                 (equivalent to realloc())
  57.  */
  58.  
  59. #ifdef PUT_THIS_IN_ROUTINE_CALLING_ME
  60. /*
  61.  * Memory sub-system, written by Bjorn Benson
  62.  */
  63. extern char *_mymalloc ();
  64. #define    NEW(SZ)        _mymalloc( SZ, __FILE__, __LINE__ )
  65. #define    FREE(PTR)    _myfree( PTR, __FILE__, __LINE__ )
  66. #endif
  67.  
  68. /*
  69.  * Memory sub-system, written by Bjorn Benson
  70.  */
  71.  
  72. #include <stdio.h>
  73.  
  74. typedef unsigned uns;            /* Shorthand */
  75.  
  76. struct irem {
  77.     struct remember *_pNext;        /* Linked list of structures       */
  78.     struct remember *_pPrev;        /* Other link               */
  79.     char *_sFileName;            /* File in which memory was new'ed */
  80.     uns _uLineNum;            /* Line number in above file       */
  81.     uns _uDataSize;            /* Size requested           */
  82.     uns _lSpecialValue;            /* Underrun marker value       */
  83. };
  84.  
  85. struct remember {
  86.     struct irem tInt;
  87.     char aData[1];
  88. };
  89.  
  90. #define    pNext        tInt._pNext
  91. #define    pPrev        tInt._pPrev
  92. #define    sFileName    tInt._sFileName
  93. #define    uLineNum    tInt._uLineNum
  94. #define    uDataSize    tInt._uDataSize
  95. #define    lSpecialValue    tInt._lSpecialValue
  96.  
  97. /*
  98.  *    Note: both these refer to the NEW'ed
  99.  *    data only.  They do not include
  100.  *    malloc() roundoff or the extra
  101.  *    space required by the remember
  102.  *    structures.
  103.  */
  104.  
  105. static long lCurMemory = 0;        /* Current memory usage    */
  106. static long lMaxMemory = 0;        /* Maximum memory usage    */
  107.  
  108. static  uns cNewCount = 0;        /* Number of times NEW() was called */
  109.  
  110.  /* Root of the linked list of remembers     */
  111. static struct remember *pRememberRoot = NULL;
  112.  
  113. #define    ALLOC_VAL    0xA5    /* NEW'ed memory is filled with this */
  114.                 /* value so that references to it will     */
  115.                 /* end up being very strange.         */
  116. #define    FREE_VAL    0x8F    /* FREE'ed memory is filled with this */
  117.                 /* value so that references to it will     */
  118.                 /* also end up being strange.         */
  119.  
  120. #define    MAGICKEY    0x14235296    /* A magic value for underrun key */
  121. #define    MAGICEND0    0x68        /* Magic values for overrun keys  */
  122. #define    MAGICEND1    0x34        /*         "          */
  123. #define    MAGICEND2    0x7A        /*              "          */
  124. #define    MAGICEND3    0x15        /*         "          */
  125.  
  126.  /* Warning: do not change the MAGICEND? values to */
  127.  /* something with the high bit set.  Various C    */
  128.  /* compilers (like the 4.2bsd one) do not do the  */
  129.  /* sign extension right later on in this code and */
  130.  /* you will get erroneous errors.          */
  131.  
  132. static void _sanity ();
  133. static void _checkchunk ();
  134.  
  135. /*
  136.  * char * _mymalloc( uns uSize, char *sFile, uns uLine )
  137.  *    Allocate some memory.
  138.  */
  139.  
  140. char *_mymalloc (uSize, sFile, uLine)
  141. uns uSize;
  142. char *sFile;
  143. uns uLine;
  144. {
  145.     extern char *malloc ();
  146.     struct remember *pTmp;
  147.     char *pPtr;
  148.  
  149.     _sanity (sFile, uLine);
  150.  
  151.     /* Allocate the physical memory */
  152.     pTmp = (struct remember *) malloc (
  153.             sizeof (struct irem)    /* remember data  */
  154.         + uSize                    /* size requested */
  155.         + 4                    /* overrun mark   */
  156.         );
  157.  
  158.     /* Check if there isn't anymore memory avaiable */
  159.     if (pTmp == NULL) {
  160.     fprintf (stderr, "Out of memory at line %d, \"%s\"\n", uLine, sFile);
  161.     fprintf (stderr, "\t(memory in use: %ld bytes (%ldk))\n",
  162.         lMaxMemory, (lMaxMemory + 1023L) / 1024L);
  163.     fflush (stderr);
  164.     return ((char *) NULL);
  165.     }
  166.  
  167.     /* Fill up the structure */
  168.     pTmp -> lSpecialValue = MAGICKEY;
  169.     pTmp -> aData[uSize + 0] = MAGICEND0;
  170.     pTmp -> aData[uSize + 1] = MAGICEND1;
  171.     pTmp -> aData[uSize + 2] = MAGICEND2;
  172.     pTmp -> aData[uSize + 3] = MAGICEND3;
  173.     pTmp -> sFileName = sFile;
  174.     pTmp -> uLineNum = uLine;
  175.     pTmp -> uDataSize = uSize;
  176.     pTmp -> pNext = pRememberRoot;
  177.     pTmp -> pPrev = NULL;
  178.  
  179.     /* Add this remember structure to the linked list */
  180.     if (pRememberRoot) {
  181.     pRememberRoot -> pPrev = pTmp;
  182.     }
  183.     pRememberRoot = pTmp;
  184.  
  185.     /* Keep the statistics */
  186.     lCurMemory += uSize;
  187.     if (lCurMemory > lMaxMemory) {
  188.     lMaxMemory = lCurMemory;
  189.     }
  190.     cNewCount++;
  191.  
  192.     /* Set the memory to the aribtrary wierd value */
  193.     for (pPtr = &pTmp -> aData[uSize]; pPtr > &pTmp -> aData[0];) {
  194.     *(--pPtr) = ALLOC_VAL;
  195.     }
  196.     /* Return a pointer to the real data */
  197.     return (&(pTmp -> aData[0]));
  198. }
  199.  
  200. /*
  201.  * _myfree( char *pPtr, char *sFile, uns uLine )
  202.  *    Deallocate some memory.
  203.  */
  204.  
  205. _myfree (pPtr, sFile, uLine)
  206. char *pPtr;
  207. char *sFile;
  208. uns uLine;
  209. {
  210.     struct remember *pRec;
  211.     char *pTmp;
  212.  
  213.     _sanity (sFile, uLine);
  214.     
  215.     /* Check if we have a non-null pointer */
  216.     if (pPtr == NULL) {
  217.     fprintf (stderr, "Freeing NULL pointer at line %d, \"%s\"\n",
  218.         uLine, sFile);
  219.     fflush (stderr);
  220.     return;
  221.     }
  222.  
  223.     /* Calculate the address of the remember structure */
  224.     pRec = (struct remember *) (pPtr - (sizeof (struct irem)));
  225.  
  226.     /* Check to make sure that we have a real remember structure */
  227.     /* Note: this test could fail for four reasons: */
  228.     /*  (1) The memory was already free'ed         */
  229.     /*  (2) The memory was never new'ed         */
  230.     /*  (3) There was an underrun             */
  231.     /*  (4) A stray pointer hit this location     */
  232.     /*                          */
  233.  
  234.     if (pRec -> lSpecialValue != MAGICKEY) {
  235.     fprintf (stderr, "Freeing unallocated data at line %d, \"%s\"\n",
  236.         uLine, sFile);
  237.     fflush (stderr);
  238.     return;
  239.     }
  240.  
  241.     /* Remove this structure from the linked list */
  242.     if (pRec -> pPrev) {
  243.     pRec -> pPrev -> pNext = pRec -> pNext;
  244.     } else {
  245.     pRememberRoot = pRec -> pNext;
  246.     }
  247.     if (pRec -> pNext) {
  248.     pRec -> pNext -> pPrev = pRec -> pPrev;
  249.     }
  250.  
  251.     /* Mark this data as free'ed */
  252.     for (pTmp = &pRec -> aData[pRec -> uDataSize]; pTmp > &pRec -> aData[0];){
  253.     *(--pTmp) = FREE_VAL;
  254.     }
  255.     pRec -> lSpecialValue = ~MAGICKEY;
  256.  
  257.     /* Handle the statistics */
  258.     lCurMemory -= pRec -> uDataSize;
  259.     cNewCount--;
  260.  
  261.     /* Actually free the memory */
  262.     free ((char *) pRec);
  263. }
  264.  
  265. /*
  266.  * TERMINATE()
  267.  *    Report on all the memory pieces that have not been
  268.  *    free'ed as well as the statistics.
  269.  */
  270.  
  271. TERMINATE ()
  272. {
  273.     struct remember *pPtr;
  274.  
  275.     /* Report the difference between number of calls to     */
  276.     /* NEW and the number of calls to FREE.  >0 means more     */
  277.     /* NEWs than FREEs.  <0, etc.                 */
  278.  
  279.     if (cNewCount) {
  280.     fprintf (stderr, "cNewCount: %d\n", cNewCount);
  281.     fflush (stderr);
  282.     }
  283.  
  284.     /* Report on all the memory that was allocated with NEW     */
  285.     /* but not free'ed with FREE.                 */
  286.  
  287.     if (pRememberRoot != NULL) {
  288.     fprintf (stderr, "Memory that was not free'ed:\n");
  289.     fflush (stderr);
  290.     }
  291.     pPtr = pRememberRoot;
  292.     while (pPtr) {
  293.     fprintf (stderr,
  294.         "\t%5d bytes at 0x%06x, allocated at line %3d in \"%s\"\n",
  295.         pPtr -> uDataSize, &(pPtr -> aData[0]),
  296.         pPtr -> uLineNum, pPtr -> sFileName
  297.         );
  298.     fflush (stderr);
  299.     pPtr = pPtr -> pNext;
  300.     }
  301.  
  302.     /* Report the memory usage statistics */
  303.     fprintf (stderr, "Maximum memory usage: %ld bytes (%ldk)\n",
  304.         lMaxMemory, (lMaxMemory + 1023L) / 1024L);
  305.     fflush (stderr);
  306. }
  307.  
  308. static void _checkchunk (pRec, sFile, uLine)
  309. register struct remember *pRec;
  310. char *sFile;
  311. uns uLine;
  312. {
  313.     register uns uSize;
  314.     register char *magicp;
  315.  
  316.     /* Check for a possible underrun */
  317.     if (pRec -> lSpecialValue != MAGICKEY) {
  318.     fprintf (stderr, "Memory allocated at \"%s:%d\" was underrun,",
  319.         pRec -> sFileName, pRec -> uLineNum);
  320.     fprintf (stderr, " discovered at \"%s:%d\"\n", sFile, uLine);
  321.     fflush (stderr);
  322.     }
  323.  
  324.     /* Check for a possible overrun */
  325.     uSize = pRec -> uDataSize;
  326.     magicp = &(pRec -> aData[uSize]);
  327.     if (*magicp++ != MAGICEND0 ||
  328.         *magicp++ != MAGICEND1 ||
  329.     *magicp++ != MAGICEND2 ||
  330.     *magicp++ != MAGICEND3)
  331.     {
  332.     fprintf (stderr, "Memory allocated at \"%s:%d\" was overrun,",
  333.         pRec -> sFileName, pRec -> uLineNum);
  334.     fprintf (stderr, " discovered at \"%s:%d\"\n", sFile, uLine);
  335.     fflush (stderr);
  336.     }
  337. }
  338.  
  339. static void _sanity (sFile, uLine)
  340. char *sFile;
  341. uns uLine;
  342. {
  343.     register struct remember *pTmp;
  344.  
  345.     for (pTmp = pRememberRoot; pTmp != NULL; pTmp = pTmp -> pNext) {
  346.         _checkchunk (pTmp, sFile, uLine);
  347.     }
  348. }
  349.