safemalloc.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:16k
源码类别:

MySQL数据库

开发平台:

Visual C++

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