mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-24 11:55:28 -04:00
9203fab207
git-svn-id: svn://localhost@6 8062f311-0dae-4547-b526-b8ab9ac864a5
263 lines
6.9 KiB
C++
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
|