safemalloc.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:16k
源码类别:

MySQL数据库

开发平台:

Visual C++

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