Files
GDevelop/IDE/DebugMemory.cpp
T
Florian 9203fab207 Initial import
git-svn-id: svn://localhost@6 8062f311-0dae-4547-b526-b8ab9ac864a5
2010-01-24 19:15:15 +00:00

263 lines
6.9 KiB
C++

#ifdef DEBUG_MEMORY
#define DEBUG_MEMORY_IMPLEMENTATION 1
#include "DebugMemory.h"
#ifndef WIN32
#include <unistd.h>
#endif
#define _MAX_FILE 128
// Flag that controls the logging of all allocations if enabled by DumpMemoryLogAllAllocations()
static BOOL _g_bDebugMemoryLogAllAllocations = FALSE;
// This is the data structure that holds an allocated block's information.
typedef struct
{
void *address;
DWORD size;
char file[_MAX_FILE];
DWORD line;
} ALLOC_INFO;
typedef ALLOC_INFO* LPALLOC_INFO;
// Prototypes for Adding and Deleting the breadcrumb's or the memory trail.
static void AddMemoryBreadcrumb(void *addr, DWORD asize, const char *fname, DWORD lnum);
static void AddUnallocatedBreadcrumb(void *addr);
static BOOL DelMemoryBreadcrumb(void *addr);
static void DebugMemoryLog(BOOL bAlloc, LPALLOC_INFO pInfo);
// new operator override.
void* __cdecl operator new(unsigned int size, const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddMemoryBreadcrumb(ptr, size, file, line);
return(ptr);
};
// delete operator override
void __cdecl operator delete(void *p, const char *file, int line)
{
file; // stop compiler complaint
line;
if (DelMemoryBreadcrumb(p))
free(p);
};
// delete operator override.
void __cdecl operator delete(void *p)
{
if (DelMemoryBreadcrumb(p))
free(p);
};
// new [] operator override.
void * __cdecl operator new [](unsigned int size, const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddMemoryBreadcrumb(ptr, size, file, line);
return(ptr);
};
// delete [] operator override
void __cdecl operator delete [] (void *p, const char *file, int line)
{
file; // stop compiler complaint
line;
if (DelMemoryBreadcrumb(p))
free(p);
};
// delete [] operator override
void __cdecl operator delete [] (void *p)
{
if (DelMemoryBreadcrumb(p))
free(p);
};
// debug version of malloc
void * __cdecl _debug_malloc(unsigned int size, const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddMemoryBreadcrumb(ptr, size, file, line);
return(ptr);
};
// debug version of calloc
void * __cdecl _debug_calloc(unsigned int nNum, unsigned int size, const char *file, int line)
{
void *ptr = (void *)calloc(nNum, size);
AddMemoryBreadcrumb(ptr, nNum*size, file, line);
return(ptr);
}
// debug version of free
void __cdecl _debug_free(void *p)
{
// if we did not find this address in our list, then somehow it is getting freed by
// us, but we did not allocate the block using one of the debug routines. Make note
// of this case, but free the block anyhow to avoid a leak.
if (DelMemoryBreadcrumb(p) == FALSE)
AddUnallocatedBreadcrumb(p);
free(p);
};
// global memory block allocation list.
LPALLOC_INFO allocList = NULL;
// counters needed
DWORD dwBlocksAvail = 0;
DWORD dwBlocksUsed = 0;
// If our list if full, make room for more.
void ReallocMemoryBlockList()
{
dwBlocksAvail += 100;
void * pzNewList = malloc(sizeof(ALLOC_INFO) * dwBlocksAvail);
memset(pzNewList,0,sizeof(ALLOC_INFO) * dwBlocksAvail);
if (allocList)
memcpy(pzNewList, allocList, sizeof(ALLOC_INFO) * dwBlocksUsed);
allocList = (LPALLOC_INFO) pzNewList;
}
// Add a breadcrumb to the memory trail.
void AddMemoryBreadcrumb(void *addr, DWORD asize, const char *fname, DWORD lnum)
{
LPALLOC_INFO info = NULL;
BOOL bFound = FALSE;
DWORD ii;
// if we need to create the list or grow it, do that now.
if(!allocList || dwBlocksUsed >= dwBlocksAvail) {
ReallocMemoryBlockList();
}
// try to find an unused block.
for(ii = 0; ii < dwBlocksUsed; ii++)
{
info = allocList+ii;
if(info->address == 0)
{
bFound = TRUE;
break;
}
}
if (bFound == FALSE)
{
// didn't find an unused block, so use one at the end of
// the list.
ii = dwBlocksUsed;
info = allocList+dwBlocksUsed;
dwBlocksUsed++;
}
// populate the breadcrumb
memset(info->file, 0, _MAX_FILE);
info->address = addr;
if (strlen(fname) > _MAX_FILE-1)
{
strcpy(info->file, "too long: ");
strcat(info->file, (fname+strlen(fname)-32));
}
else
strcpy(info->file, fname);
info->line = lnum;
info->size = asize;
DebugMemoryLog(TRUE, info);
};
// Add a trail for blocks we freed but we didn't allocate.
void AddUnallocatedBreadcrumb(void *addr)
{
AddMemoryBreadcrumb(addr, 0, "freed unallocated block. File unknown", 0);
}
// Delete a breadcrumb from our trail.
BOOL DelMemoryBreadcrumb(void *addr)
{
DWORD ii;
if(!allocList || dwBlocksAvail <= 0)
return FALSE;
if (addr == 0)
return FALSE;
for(ii = 0; ii < dwBlocksUsed; ii++)
{
LPALLOC_INFO info = allocList+ii;
if(info->address == addr && info->line != 0 && info->size != 0)
{
DebugMemoryLog(FALSE, info);
info->address = 0;
memset(info->file, 0, _MAX_FILE);
info->line = 0;
info->size = 0;
return TRUE;
}
}
return FALSE;
}
void DumpMemoryLogAllAllocations(BOOL bEnable)
{
_g_bDebugMemoryLogAllAllocations = bEnable;
if (bEnable)
unlink("debugmemorylog.txt"); // reset the file.
}
void DebugMemoryLog(BOOL bAlloc, LPALLOC_INFO pInfo)
{
if (_g_bDebugMemoryLogAllAllocations != TRUE)
return;
if (pInfo != NULL)
{
FILE *fp = fopen("debugmemorylog.txt","a+");
if (!fp)
return;
fprintf(fp,"%p:\t%s\t%d %s\n",pInfo->address, pInfo->file, pInfo->line,(bAlloc ? "allocated" : "freed"));
fflush(fp);
fclose(fp);
}
}
// Write the memory leak report to memoryleak.txt
void DumpUnfreed(BOOL bFreeList)
{
DWORD totalSize = 0;
DWORD ii;
char buf[1024];
FILE *fp = fopen("memoryleak.txt","w");
if(!allocList || !fp)
return;
for(ii = 0; ii < dwBlocksAvail; ii++) {
LPALLOC_INFO info = allocList+ii;
if (info->address != 0 && info->line != 0 && info->size != 0)
{
sprintf(buf, "%d:%-50s:\t\tLINE %d,\tADDRESS %p\t%d unfreed\tblock %d\n",
ii+1,info->file, info->line, info->address, info->size,ii);
fprintf(fp,buf);
totalSize += info->size;
}
}
sprintf(buf, "-----------------------------------------------------------\n");
for(ii = 0; ii < dwBlocksAvail; ii++) {
LPALLOC_INFO info = allocList+ii;
if (info->address != 0 && info->line == 0 && info->size == 0)
{
sprintf(buf, "%d:%-50s:\t\tFreed address %p that was not allocated by DebugMemory\n",
ii+1,info->file, info->address);
fprintf(fp,buf);
}
}
sprintf(buf, "-----------------------------------------------------------\n");
fprintf(fp,buf);
sprintf(buf, "Total Unfreed: %d bytes\n", totalSize);
fprintf(fp,buf);
fclose(fp);
if (bFreeList)
{
free(allocList);
allocList = NULL;
}
};
#endif