safemalloc.c
上传用户:jmzj888
上传日期:2007-01-02
资源大小:220k
文件大小:14k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
  2.    This file is public domain and comes with NO WARRANTY of any kind */
  3. /*
  4.  * [This posting refers to an article entitled "oops, corrupted memory
  5.  * again!" in net.lang.c.  I am posting it here because it is source.]
  6.  *
  7.  * My tool for approaching this problem is to build another level of data
  8.  * abstraction on top of malloc() and free() that implements some checking.
  9.  * This does a number of things for you:
  10.  * - Checks for overruns and underruns on allocated data
  11.  * - Keeps track of where in the program the memory was malloc'ed
  12.  * - Reports on pieces of memory that were not free'ed
  13.  * - Records some statistics such as maximum memory used
  14.  * - Marks newly malloc'ed and newly free'ed memory with special values
  15.  * You can use this scheme to:
  16.  * - Find bugs such as overrun, underrun, etc because you know where
  17.  *   a piece of data was malloc'ed and where it was free'ed
  18.  * - Find bugs where memory was not free'ed
  19.  * - Find bugs where newly malloc'ed memory is used without initializing
  20.  * - Find bugs where newly free'ed memory is still used
  21.  * - Determine how much memory your program really uses
  22.  * - and other things
  23.  */
  24. /*
  25.  * To implement my scheme you must have a C compiler that has __LINE__ and
  26.  * __FILE__ macros.  If your compiler doesn't have these then (a) buy another:
  27.  * compilers that do are available on UNIX 4.2bsd based systems and the PC,
  28.  * and probably on other machines; or (b) change my scheme somehow.  I have
  29.  * recomendations on both these points if you would like them (e-mail please).
  30.  *
  31.  * There are 4 functions in my package:
  32.  * char *NEW( uSize ) Allocate memory of uSize bytes
  33.  * (equivalent to malloc())
  34.  * char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and
  35.  * free pPtr.
  36.  * (equivalent to realloc())
  37.  * FREE( pPtr ) Free memory allocated by NEW
  38.  * (equivalent to free())
  39.  * TERMINATE(file) End system, report errors and stats on file
  40.  * I personally use two more functions, but have not included them here:
  41.  * char *STRSAVE( sPtr ) Save a copy of the string in dynamic memory
  42.  * char *RENEW( pPtr, uSize )
  43.  * (equivalent to realloc())
  44.  */
  45. /*
  46.  * Memory sub-system, written by Bjorn Benson
  47.    Fixed to use my_sys scheme by Michael Widenius
  48.  */
  49. #ifndef SAFEMALLOC
  50. #define SAFEMALLOC /* Get protos from my_sys */
  51. #endif
  52. #include "mysys_priv.h"
  53. #include <m_string.h>
  54. #include "my_static.h"
  55. #include "mysys_err.h"
  56. #define pNext tInt._pNext
  57. #define pPrev tInt._pPrev
  58. #define sFileName tInt._sFileName
  59. #define uLineNum tInt._uLineNum
  60. #define uDataSize tInt._uDataSize
  61. #define lSpecialValue tInt._lSpecialValue
  62. /* Static functions prototypes */
  63. static int check_ptr(my_string where,byte *ptr,const char *sFile, uint uLine);
  64. static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);
  65. /*
  66.  * Note: both these refer to the NEW'ed
  67.  * data only.  They do not include
  68.  * malloc() roundoff or the extra
  69.  * space required by the remember
  70.  * structures.
  71.  */
  72. #define ALLOC_VAL (uchar) 0xA5 /* NEW'ed memory is filled with this */
  73. /* value so that references to it will  */
  74. /* end up being very strange.  */
  75. #define FREE_VAL (uchar) 0x8F /* FREE'ed memory is filled with this */
  76. /* value so that references to it will  */
  77. /* also end up being strange.  */
  78. #define MAGICKEY 0x14235296 /* A magic value for underrun key */
  79. #define MAGICEND0 0x68 /* Magic values for overrun keys  */
  80. #define MAGICEND1 0x34 /* "   */
  81. #define MAGICEND2 0x7A /* "   */
  82. #define MAGICEND3 0x15 /* "   */
  83.  /* Warning: do not change the MAGICEND? values to */
  84.  /* something with the high bit set.  Various C    */
  85.  /* compilers (like the 4.2bsd one) do not do the  */
  86.  /* sign extension right later on in this code and */
  87.  /* you will get erroneous errors.   */
  88. /*
  89.  * gptr _mymalloc( uint uSize, my_string sFile, uint uLine, MyFlags )
  90.  * Allocate some memory.
  91.  */
  92. gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags)
  93. {
  94.     struct remember *pTmp;
  95.     DBUG_ENTER("_mymalloc");
  96.     DBUG_PRINT("enter",("Size: %u",uSize));
  97.     if (!sf_malloc_quick)
  98.       (void) _sanity (sFile, uLine);
  99.     /* Allocate the physical memory */
  100.     pTmp = (struct remember *) malloc (
  101. sizeof (struct irem) /* remember data  */
  102. + sf_malloc_prehunc
  103. + uSize /* size requested */
  104. + 4 /* overrun mark   */
  105. + sf_malloc_endhunc
  106. );
  107.     /* Check if there isn't anymore memory avaiable */
  108.     if (pTmp == NULL)
  109.     {
  110.       if (MyFlags & MY_FAE)
  111. error_handler_hook=fatal_error_handler_hook;
  112.       if (MyFlags & (MY_FAE+MY_WME))
  113.       {
  114. char buff[SC_MAXWIDTH];
  115. my_errno=errno;
  116. sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile);
  117. my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
  118. sprintf(buff,"neaded %d byte (%ldk), memory in use: %ld bytes (%ldk))",
  119. uSize, (uSize + 1023L) / 1024L,
  120. lMaxMemory, (lMaxMemory + 1023L) / 1024L);
  121. my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
  122.       }
  123.       DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
  124.   lMaxMemory,uLine, sFile));
  125.       if (MyFlags & MY_FAE)
  126. exit(1);
  127.       DBUG_RETURN ((gptr) NULL);
  128.     }
  129.     /* Fill up the structure */
  130.     *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY;
  131.     pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0;
  132.     pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1;
  133.     pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2;
  134.     pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3;
  135.     pTmp -> sFileName = (my_string) sFile;
  136.     pTmp -> uLineNum = uLine;
  137.     pTmp -> uDataSize = uSize;
  138.     pTmp -> pPrev = NULL;
  139.     /* Add this remember structure to the linked list */
  140.     pthread_mutex_lock(&THR_LOCK_malloc);
  141.     if ((pTmp->pNext=pRememberRoot))
  142.     {
  143.       pRememberRoot -> pPrev = pTmp;
  144.     }
  145.     pRememberRoot = pTmp;
  146.     /* Keep the statistics */
  147.     lCurMemory += uSize;
  148.     if (lCurMemory > lMaxMemory) {
  149. lMaxMemory = lCurMemory;
  150.     }
  151.     cNewCount++;
  152.     pthread_mutex_unlock(&THR_LOCK_malloc);
  153.     /* Set the memory to the aribtrary wierd value */
  154. #ifdef HAVE_purify
  155.     if (MyFlags & MY_ZEROFILL)
  156. #endif
  157.       bfill(&pTmp -> aData[sf_malloc_prehunc],uSize,
  158.     (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
  159.     /* Return a pointer to the real data */
  160.     DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc])));
  161.     if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc]))
  162.       sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]);
  163.     if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc]))
  164.       sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]);
  165.     DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));
  166. }
  167. /*
  168.  *  Allocate some new memory and move old memoryblock there.
  169.  *  Free then old memoryblock
  170.  */
  171. gptr _myrealloc (register my_string pPtr, register uint uSize,
  172.  const char *sFile, uint uLine, myf MyFlags)
  173. {
  174.   struct remember *pRec;
  175.   gptr ptr;
  176.   DBUG_ENTER("_myrealloc");
  177.   if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR))
  178.     DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags));
  179.   if (!sf_malloc_quick)
  180.     (void) _sanity (sFile, uLine);
  181.   if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine))
  182.     DBUG_RETURN((gptr) NULL);
  183.   pRec = (struct remember *) (pPtr - sizeof (struct irem)-sf_malloc_prehunc);
  184.   if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
  185.       != MAGICKEY)
  186.   {
  187.     fprintf (stderr, "Reallocating unallocated data at line %d, '%s'n",
  188.      uLine, sFile);
  189.     DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
  190.        uLine, sFile));
  191.     (void) fflush(stderr);
  192.     DBUG_RETURN((gptr) NULL);
  193.   }
  194.   if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */
  195.   {
  196.     uSize=min(uSize,pRec-> uDataSize); /* Move as much as possibly */
  197.     memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */
  198.     _myfree(pPtr,sFile,uLine,0); /* Free not needed area */
  199.   }
  200.   else
  201.   {
  202.     if (MyFlags & MY_HOLD_ON_ERROR)
  203.       DBUG_RETURN(pPtr);
  204.     if (MyFlags & MY_FREE_ON_ERROR)
  205.       _myfree(pPtr,sFile,uLine,0);
  206.   }
  207.   DBUG_RETURN(ptr);
  208. } /* _myrealloc */
  209. /*
  210.  * void _myfree( my_string pPtr, my_string sFile, uint uLine, myf myflags)
  211.  * Deallocate some memory.
  212.  */
  213. void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags)
  214. {
  215.   struct remember *pRec;
  216.   DBUG_ENTER("_myfree");
  217.   DBUG_PRINT("enter",("ptr: %lx",pPtr));
  218.   if (!sf_malloc_quick)
  219.     (void) _sanity (sFile, uLine);
  220.   if (!pPtr && (myflags & MY_ALLOW_ZERO_PTR) ||
  221.       check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
  222.     DBUG_VOID_RETURN;
  223.   /* Calculate the address of the remember structure */
  224.   pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
  225.       sf_malloc_prehunc);
  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.   if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
  233.       != MAGICKEY)
  234.   {
  235.     fprintf (stderr, "Freeing unallocated data at line %d, '%s'n",
  236.      uLine, sFile);
  237.     DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile));
  238.     (void) fflush(stderr);
  239.     DBUG_VOID_RETURN;
  240.   }
  241.   /* Remove this structure from the linked list */
  242.   pthread_mutex_lock(&THR_LOCK_malloc);
  243.   if (pRec -> pPrev) {
  244.     pRec -> pPrev -> pNext = pRec -> pNext;
  245.   } else {
  246.     pRememberRoot = pRec -> pNext;
  247.   }
  248.   if (pRec -> pNext) {
  249.     pRec -> pNext -> pPrev = pRec -> pPrev;
  250.   }
  251.   /* Handle the statistics */
  252.   lCurMemory -= pRec -> uDataSize;
  253.   cNewCount--;
  254.   pthread_mutex_unlock(&THR_LOCK_malloc);
  255. #ifndef HAVE_purify
  256.   /* Mark this data as free'ed */
  257.   bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL);
  258. #endif
  259.   *((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY;
  260.   /* Actually free the memory */
  261.   free ((my_string ) pRec);
  262.   DBUG_VOID_RETURN;
  263. }
  264. /* Check if we have a wrong  pointer */
  265. static int check_ptr(my_string where, byte *ptr, const char *sFile, uint uLine)
  266. {
  267.   if (!ptr)
  268.   {
  269.     fprintf (stderr, "%s NULL pointer at line %d, '%s'n",
  270.      where,uLine, sFile);
  271.     DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
  272.     (void) fflush(stderr);
  273.     return 1;
  274.   }
  275. #ifndef _MSC_VER
  276.   if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
  277.   {
  278.     fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'n",
  279.      where,uLine, sFile);
  280.     DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
  281.        uLine,sFile));
  282.     (void) fflush(stderr);
  283.     return 1;
  284.   }
  285. #endif
  286.   if (ptr < sf_min_adress || ptr > sf_max_adress)
  287.   {
  288.     fprintf (stderr, "%s pointer out of range at line %d, '%s'n",
  289.      where,uLine, sFile);
  290.     DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
  291.        uLine,sFile));
  292.     (void) fflush(stderr);
  293.     return 1;
  294.   }
  295.   return 0;
  296. }
  297. /*
  298.  * TERMINATE(FILE *file)
  299.  * Report on all the memory pieces that have not been
  300.  * free'ed as well as the statistics.
  301.  */
  302. void TERMINATE (FILE *file)
  303. {
  304.   struct remember *pPtr;
  305.   DBUG_ENTER("TERMINATE");
  306.   pthread_mutex_lock(&THR_LOCK_malloc);
  307.   /* Report the difference between number of calls to  */
  308.   /* NEW and the number of calls to FREE.  >0 means more  */
  309.   /* NEWs than FREEs.  <0, etc.  */
  310.   if (cNewCount) {
  311.     fprintf (file, "cNewCount: %dn", cNewCount);
  312.     (void) fflush(file);
  313.   }
  314.   /* Report on all the memory that was allocated with NEW  */
  315.   /* but not free'ed with FREE.  */
  316.   if (pRememberRoot != NULL) {
  317.     fprintf (file, "Memory that was not free'ed:n");
  318.     (void) fflush(file);
  319.     DBUG_PRINT("safe",("Memory that was not free'ed:"));
  320.   }
  321.   pPtr = pRememberRoot;
  322.   while (pPtr) {
  323.     fprintf (file,
  324.      "t%6u bytes at 0x%09lx, allocated at line %4d in '%s'n",
  325.      pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
  326.      pPtr -> uLineNum, pPtr -> sFileName
  327.      );
  328.     DBUG_PRINT("safe",
  329.        ("%6u bytes at 0x%09lx, allocated at line %4d in '%s'",
  330. pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
  331. pPtr -> uLineNum, pPtr -> sFileName
  332. ));
  333.     (void) fflush(file);
  334.     pPtr = pPtr -> pNext;
  335.   }
  336.   /* Report the memory usage statistics */
  337.   fprintf (file, "Maximum memory usage: %ld bytes (%ldk)n",
  338.    lMaxMemory, (lMaxMemory + 1023L) / 1024L);
  339.   (void) fflush(file);
  340.   pthread_mutex_unlock(&THR_LOCK_malloc);
  341.   DBUG_VOID_RETURN;
  342. }
  343. /* Returns 0 if chunk is ok */
  344. static int _checkchunk (register struct remember *pRec, const char *sFile,
  345. uint uLine)
  346. {
  347.   reg1 uint uSize;
  348.   reg2 my_string magicp;
  349.   reg3 int flag=0;
  350.   /* Check for a possible underrun */
  351.   if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
  352.       != MAGICKEY)
  353.   {
  354.     fprintf (stderr, "Memory allocated at %s:%d was underrun,",
  355.      pRec -> sFileName, pRec -> uLineNum);
  356.     fprintf (stderr, " discovered at %s:%dn", sFile, uLine);
  357.     (void) fflush(stderr);
  358.     DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d",
  359.        &(pRec -> aData[sf_malloc_prehunc]),
  360.        pRec -> sFileName,
  361.        pRec -> uLineNum));
  362.     flag=1;
  363.   }
  364.   /* Check for a possible overrun */
  365.   uSize = pRec -> uDataSize;
  366.   magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]);
  367.   if (*magicp++ != MAGICEND0 ||
  368.       *magicp++ != MAGICEND1 ||
  369.       *magicp++ != MAGICEND2 ||
  370.       *magicp++ != MAGICEND3)
  371.   {
  372.     fprintf (stderr, "Memory allocated at %s:%d was overrun,",
  373.      pRec -> sFileName, pRec -> uLineNum);
  374.     fprintf (stderr, " discovered at '%s:%d'n", sFile, uLine);
  375.     (void) fflush(stderr);
  376.     DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d",
  377.        &(pRec -> aData[sf_malloc_prehunc]),
  378.        pRec -> sFileName,
  379.        pRec -> uLineNum));
  380.     flag=1;
  381.   }
  382.   return(flag);
  383. }
  384. /* Returns how many wrong chunks */
  385. int _sanity (const char *sFile, uint uLine)
  386. {
  387.   reg1 struct remember *pTmp;
  388.   reg2 int flag=0;
  389.   pthread_mutex_lock(&THR_LOCK_malloc);
  390.   for (pTmp = pRememberRoot; pTmp != NULL; pTmp = pTmp -> pNext)
  391.     flag+=_checkchunk (pTmp, sFile, uLine);
  392.   pthread_mutex_unlock(&THR_LOCK_malloc);
  393.   return flag;
  394. } /* _sanity */
  395. /* malloc and copy */
  396. gptr _my_memdup(const byte *from, uint length, const char *sFile, uint uLine,
  397. myf MyFlags)
  398. {
  399.   gptr ptr;
  400.   if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
  401.     memcpy((byte*) ptr, (byte*) from,(size_t) length);
  402.   return(ptr);
  403. } /*_my_memdup */
  404. my_string _my_strdup(const char *from, const char *sFile, uint uLine,
  405.      myf MyFlags)
  406. {
  407.   gptr ptr;
  408.   uint length=(uint) strlen(from)+1;
  409.   if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
  410.     memcpy((byte*) ptr, (byte*) from,(size_t) length);
  411.   return((my_string) ptr);
  412. } /* _my_strdup */