#ifndef SAFEMALLOC
#define SAFEMALLOC
#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 int check_ptr(const char *where, byte *ptr, const char *sFile,
uint uLine);
static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);
#define ALLOC_VAL (uchar) 0xA5
#define FREE_VAL (uchar) 0x8F
#define MAGICKEY 0x14235296
#define MAGICEND0 0x68
#define MAGICEND1 0x34
#define MAGICEND2 0x7A
#define MAGICEND3 0x15
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
pTmp = (struct remember *) malloc (
sizeof (struct irem)
+ sf_malloc_prehunc
+ uSize
+ 4
+ sf_malloc_endhunc
);
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);
}
*((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;
pthread_mutex_lock(&THR_LOCK_malloc);
if ((pTmp->pNext=pRememberRoot))
{
pRememberRoot -> pPrev = pTmp;
}
pRememberRoot = pTmp;
lCurMemory += uSize;
if (lCurMemory > lMaxMemory) {
lMaxMemory = lCurMemory;
}
cNewCount++;
pthread_mutex_unlock(&THR_LOCK_malloc);
#ifdef HAVE_purify
if (MyFlags & MY_ZEROFILL)
#endif
bfill(&pTmp -> aData[sf_malloc_prehunc],uSize,
(char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
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]));
}
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)))
{
uSize=min(uSize,pRec-> uDataSize);
memcpy((byte*) ptr,pPtr,(size_t) uSize);
_myfree(pPtr,sFile,uLine,0);
}
else
{
if (MyFlags & MY_HOLD_ON_ERROR)
DBUG_RETURN(pPtr);
if (MyFlags & MY_FREE_ON_ERROR)
_myfree(pPtr,sFile,uLine,0);
}
DBUG_RETURN(ptr);
}
void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags)
{
struct remember *pRec;
DBUG_ENTER("_myfree");
DBUG_PRINT("enter",("ptr: %lx",pPtr));
if (!sf_malloc_quick)
(void) _sanity (sFile, uLine);
if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) ||
check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
DBUG_VOID_RETURN;
pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
sf_malloc_prehunc);
if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
!= MAGICKEY)
{
fprintf (stderr, "Freeing unallocated data at line %d, '%s'\n",
uLine, sFile);
DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile));
(void) fflush(stderr);
DBUG_VOID_RETURN;
}
pthread_mutex_lock(&THR_LOCK_malloc);
if (pRec -> pPrev) {
pRec -> pPrev -> pNext = pRec -> pNext;
} else {
pRememberRoot = pRec -> pNext;
}
if (pRec -> pNext) {
pRec -> pNext -> pPrev = pRec -> pPrev;
}
lCurMemory -= pRec -> uDataSize;
cNewCount--;
pthread_mutex_unlock(&THR_LOCK_malloc);
#ifndef HAVE_purify
bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL);
#endif
*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY;
free ((my_string ) pRec);
DBUG_VOID_RETURN;
}
static int check_ptr(const char *where, byte *ptr, const char *sFile,
uint uLine)
{
if (!ptr)
{
fprintf (stderr, "%s NULL pointer at line %d, '%s'\n",
where,uLine, sFile);
DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
(void) fflush(stderr);
return 1;
}
#ifndef _MSC_VER
if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
{
fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'\n",
where,uLine, sFile);
DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
uLine,sFile));
(void) fflush(stderr);
return 1;
}
#endif
if (ptr < sf_min_adress || ptr > sf_max_adress)
{
fprintf (stderr, "%s pointer out of range at line %d, '%s'\n",
where,uLine, sFile);
DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
uLine,sFile));
(void) fflush(stderr);
return 1;
}
return 0;
}
void TERMINATE (FILE *file)
{
struct remember *pPtr;
DBUG_ENTER("TERMINATE");
pthread_mutex_lock(&THR_LOCK_malloc);
if (cNewCount)
{
if (file)
{
fprintf (file, "cNewCount: %d\n", cNewCount);
(void) fflush(file);
}
DBUG_PRINT("safe",("cNewCount: %d",cNewCount));
}
if ((pPtr=pRememberRoot))
{
if (file)
{
fprintf(file, "Memory that was not free'ed (%ld bytes):\n",lCurMemory);
(void) fflush(file);
}
DBUG_PRINT("safe",("Memory that was not free'ed (%ld bytes):",lCurMemory));
while (pPtr)
{
if (file)
{
fprintf (file,
"\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'\n",
pPtr -> uDataSize,
(ulong) &(pPtr -> aData[sf_malloc_prehunc]),
pPtr -> uLineNum, pPtr -> sFileName);
(void) fflush(file);
}
DBUG_PRINT("safe",
("%6u bytes at 0x%09lx, allocated at line %4d in '%s'",
pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
pPtr -> uLineNum, pPtr -> sFileName));
pPtr = pPtr -> pNext;
}
}
if (file)
{
fprintf (file, "Maximum memory usage: %ld bytes (%ldk)\n",
lMaxMemory, (lMaxMemory + 1023L) / 1024L);
(void) fflush(file);
}
DBUG_PRINT("safe",("Maximum memory usage: %ld bytes (%ldk)",
lMaxMemory, (lMaxMemory + 1023L) / 1024L));
pthread_mutex_unlock(&THR_LOCK_malloc);
DBUG_VOID_RETURN;
}
static int _checkchunk (register struct remember *pRec, const char *sFile,
uint uLine)
{
reg1 uint uSize;
reg2 my_string magicp;
reg3 int flag=0;
if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
!= MAGICKEY)
{
fprintf (stderr, "Memory allocated at %s:%d was underrun,",
pRec -> sFileName, pRec -> uLineNum);
fprintf (stderr, " discovered at %s:%d\n", sFile, uLine);
(void) fflush(stderr);
DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d",
&(pRec -> aData[sf_malloc_prehunc]),
pRec -> sFileName,
pRec -> uLineNum));
flag=1;
}
uSize = pRec -> uDataSize;
magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]);
if (*magicp++ != MAGICEND0 ||
*magicp++ != MAGICEND1 ||
*magicp++ != MAGICEND2 ||
*magicp++ != MAGICEND3)
{
fprintf (stderr, "Memory allocated at %s:%d was overrun,",
pRec -> sFileName, pRec -> uLineNum);
fprintf (stderr, " discovered at '%s:%d'\n", sFile, uLine);
(void) fflush(stderr);
DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d",
&(pRec -> aData[sf_malloc_prehunc]),
pRec -> sFileName,
pRec -> uLineNum));
flag=1;
}
return(flag);
}
int _sanity (const char *sFile, uint uLine)
{
reg1 struct remember *pTmp;
reg2 int flag=0;
uint count=0;
pthread_mutex_lock(&THR_LOCK_malloc);
count=cNewCount;
for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext)
flag+=_checkchunk (pTmp, sFile, uLine);
pthread_mutex_unlock(&THR_LOCK_malloc);
if (count || pTmp)
{
const char *format="Safemalloc link list destroyed, discovered at '%s:%d'";
fprintf (stderr, format, sFile, uLine); fputc('\n',stderr);
(void) fflush(stderr);
DBUG_PRINT("safe",(format, sFile, uLine));
flag=1;
}
return flag;
}
gptr _my_memdup(const byte *from, uint length, const char *sFile, uint uLine,
myf MyFlags)
{
gptr ptr;
if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
memcpy((byte*) ptr, (byte*) from,(size_t) length);
return(ptr);
}
my_string _my_strdup(const char *from, const char *sFile, uint uLine,
myf MyFlags)
{
gptr ptr;
uint length=(uint) strlen(from)+1;
if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
memcpy((byte*) ptr, (byte*) from,(size_t) length);
return((my_string) ptr);
}