📄 safemalloc.c
字号:
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB This file is public domain and comes with NO WARRANTY of any kind *//* * [This posting refers to an article entitled "oops, corrupted memory * again!" in net.lang.c. I am posting it here because it is source.] * * My tool for approaching this problem is to build another level of data * abstraction on top of malloc() and free() that implements some checking. * This does a number of things for you: * - Checks for overruns and underruns on allocated data * - Keeps track of where in the program the memory was malloc'ed * - Reports on pieces of memory that were not free'ed * - Records some statistics such as maximum memory used * - Marks newly malloc'ed and newly free'ed memory with special values * You can use this scheme to: * - Find bugs such as overrun, underrun, etc because you know where * a piece of data was malloc'ed and where it was free'ed * - Find bugs where memory was not free'ed * - Find bugs where newly malloc'ed memory is used without initializing * - Find bugs where newly free'ed memory is still used * - Determine how much memory your program really uses * - and other things *//* * To implement my scheme you must have a C compiler that has __LINE__ and * __FILE__ macros. If your compiler doesn't have these then (a) buy another: * compilers that do are available on UNIX 4.2bsd based systems and the PC, * and probably on other machines; or (b) change my scheme somehow. I have * recomendations on both these points if you would like them (e-mail please). * * There are 4 functions in my package: * char *NEW( uSize ) Allocate memory of uSize bytes * (equivalent to malloc()) * char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and * free pPtr. * (equivalent to realloc()) * FREE( pPtr ) Free memory allocated by NEW * (equivalent to free()) * TERMINATE(file) End system, report errors and stats on file * I personally use two more functions, but have not included them here: * char *STRSAVE( sPtr ) Save a copy of the string in dynamic memory * char *RENEW( pPtr, uSize ) * (equivalent to realloc()) *//* * Memory sub-system, written by Bjorn Benson Fixed to use my_sys scheme by Michael Widenius */#ifndef SAFEMALLOC#define SAFEMALLOC /* Get protos from my_sys */#endif#include "mysys_priv.h"#include <m_string.h>#include "my_static.h"#include "mysys_err.h"ulonglong safemalloc_mem_limit = ~(ulonglong)0;#define pNext tInt._pNext#define pPrev tInt._pPrev#define sFileName tInt._sFileName#define uLineNum tInt._uLineNum#define uDataSize tInt._uDataSize#define lSpecialValue tInt._lSpecialValue /* Static functions prototypes */static int check_ptr(const char *where, byte *ptr, const char *sFile, uint uLine);static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);/* * Note: both these refer to the NEW'ed * data only. They do not include * malloc() roundoff or the extra * space required by the remember * structures. */#define ALLOC_VAL (uchar) 0xA5 /* NEW'ed memory is filled with this */ /* value so that references to it will */ /* end up being very strange. */#define FREE_VAL (uchar) 0x8F /* FREE'ed memory is filled with this */ /* value so that references to it will */ /* also end up being strange. */#define MAGICKEY 0x14235296 /* A magic value for underrun key */#define MAGICEND0 0x68 /* Magic values for overrun keys */#define MAGICEND1 0x34 /* " */#define MAGICEND2 0x7A /* " */#define MAGICEND3 0x15 /* " */ /* Warning: do not change the MAGICEND? values to */ /* something with the high bit set. Various C */ /* compilers (like the 4.2bsd one) do not do the */ /* sign extension right later on in this code and */ /* you will get erroneous errors. *//* * gptr _mymalloc( uint uSize, my_string sFile, uint uLine, MyFlags ) * Allocate some memory. */gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags){ struct remember *pTmp; DBUG_ENTER("_mymalloc"); DBUG_PRINT("enter",("Size: %u",uSize)); if (!sf_malloc_quick) (void) _sanity (sFile, uLine); if(uSize + lCurMemory > safemalloc_mem_limit) pTmp = 0; else /* Allocate the physical memory */ pTmp = (struct remember *) malloc ( sizeof (struct irem) /* remember data */ + sf_malloc_prehunc + uSize /* size requested */ + 4 /* overrun mark */ + sf_malloc_endhunc ); /* Check if there isn't anymore memory avaiable */ if (pTmp == NULL) { if (MyFlags & MY_FAE) error_handler_hook=fatal_error_handler_hook; if (MyFlags & (MY_FAE+MY_WME)) { char buff[SC_MAXWIDTH]; my_errno=errno; sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile); my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); sprintf(buff,"needed %d byte (%ldk), memory in use: %ld bytes (%ldk)", uSize, (uSize + 1023L) / 1024L, lMaxMemory, (lMaxMemory + 1023L) / 1024L); my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG)); } DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'", lMaxMemory,uLine, sFile)); if (MyFlags & MY_FAE) exit(1); DBUG_RETURN ((gptr) NULL); } /* Fill up the structure */ *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY; pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0; pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1; pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2; pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3; pTmp -> sFileName = (my_string) sFile; pTmp -> uLineNum = uLine; pTmp -> uDataSize = uSize; pTmp -> pPrev = NULL; /* Add this remember structure to the linked list */ pthread_mutex_lock(&THR_LOCK_malloc); if ((pTmp->pNext=pRememberRoot)) { pRememberRoot -> pPrev = pTmp; } pRememberRoot = pTmp; /* Keep the statistics */ lCurMemory += uSize; if (lCurMemory > lMaxMemory) { lMaxMemory = lCurMemory; } cNewCount++; pthread_mutex_unlock(&THR_LOCK_malloc); /* Set the memory to the aribtrary wierd value */#ifdef HAVE_purify if (MyFlags & MY_ZEROFILL)#endif bfill(&pTmp -> aData[sf_malloc_prehunc],uSize, (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL)); /* Return a pointer to the real data */ DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc]))); if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc])) sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]); if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc])) sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]); DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));}/* * Allocate some new memory and move old memoryblock there. * Free then old memoryblock */gptr _myrealloc (register gptr pPtr, register uint uSize, const char *sFile, uint uLine, myf MyFlags){ struct remember *pRec; gptr ptr; DBUG_ENTER("_myrealloc"); if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR)) DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags)); if (!sf_malloc_quick) (void) _sanity (sFile, uLine); if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine)) DBUG_RETURN((gptr) NULL); pRec = (struct remember *) ((char*) pPtr - sizeof (struct irem)- sf_malloc_prehunc); if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) != MAGICKEY) { fprintf (stderr, "Reallocating unallocated data at line %d, '%s'\n", uLine, sFile); DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'", uLine, sFile)); (void) fflush(stderr); DBUG_RETURN((gptr) NULL); } if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */ { uSize=min(uSize,pRec-> uDataSize); /* Move as much as possibly */ memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */ _myfree(pPtr,sFile,uLine,0); /* Free not needed area */ } else { if (MyFlags & MY_HOLD_ON_ERROR) DBUG_RETURN(pPtr); if (MyFlags & MY_FREE_ON_ERROR) _myfree(pPtr,sFile,uLine,0); } DBUG_RETURN(ptr);} /* _myrealloc *//* * void _myfree( my_string pPtr, my_string sFile, uint uLine, myf myflags) * Deallocate some memory. */void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags){ struct remember *pRec; DBUG_ENTER("_myfree");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -