Blame |
Last modification |
View Log
| RSS feed
#include "Common.h"
#include "Debug.h"
#include "AutoCrit.h"
#include "CritSect.h"
#include <time.h>
#include "memmgr.h"
extern bool gInAssert = false;
extern bool gSexyDumpLeakedMem = false;
static FILE *gTraceFile = NULL;
static int gTraceFileLen = 0;
static int gTraceFileNum = 1;
using namespace Sexy;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
struct SEXY_ALLOC_INFO
{
int size;
char file[_MAX_PATH+1];
int line;
};
static bool gShowLeaks = false;
static bool gSexyAllocMapValid = false;
class SexyAllocMap : public std::map<void*,SEXY_ALLOC_INFO>
{
public:
CritSect mCrit;
public:
SexyAllocMap() { gSexyAllocMapValid = true; }
~SexyAllocMap()
{
if (gShowLeaks)
SexyDumpUnfreed();
gSexyAllocMapValid = false;
}
};
static SexyAllocMap gSexyAllocMap;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SexyTrace(const char *theStr)
{
if (gTraceFile==NULL)
{
gTraceFileNum = (gTraceFileNum+1)%2;
char aBuf[50];
sprintf(aBuf,"trace%d.txt",gTraceFileNum+1);
gTraceFile = fopen(aBuf,"w");
if (gTraceFile==NULL)
return;
}
fprintf(gTraceFile,"%s\n",theStr);
fflush(gTraceFile);
gTraceFileLen += strlen(theStr);
if (gTraceFileLen > 100000)
{
fclose(gTraceFile);
gTraceFile = NULL;
gTraceFileLen = 0;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void SexyTraceFmt(const SexyChar* fmt ...)
{
// Does not append a newline by default, also takes vararg parameters
va_list argList;
va_start(argList, fmt);
std::string result = SexyStringToStringFast(vformat(fmt, argList));
va_end(argList);
if (gTraceFile==NULL)
{
gTraceFileNum = (gTraceFileNum+1)%2;
char aBuf[50];
sprintf(aBuf,"trace%d.txt",gTraceFileNum+1);
gTraceFile = fopen(aBuf,"w");
if (gTraceFile==NULL)
return;
}
fprintf(gTraceFile,"%s",result.c_str());
fflush(gTraceFile);
gTraceFileLen += result.length();
if (gTraceFileLen > 100000)
{
fclose(gTraceFile);
gTraceFile = NULL;
gTraceFileLen = 0;
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SexyMemAddTrack(void *addr, int asize, const char* fname, int lnum)
{
if (!gSexyAllocMapValid)
return;
AutoCrit aCrit(gSexyAllocMap.mCrit);
gShowLeaks = true;
SEXY_ALLOC_INFO &info = gSexyAllocMap[addr];
strncpy(info.file, fname, sizeof(info.file)-1);
info.line = lnum;
info.size = asize;
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SexyMemRemoveTrack(void* addr)
{
if (!gSexyAllocMapValid)
return;
AutoCrit aCrit(gSexyAllocMap.mCrit);
SexyAllocMap::iterator anItr = gSexyAllocMap.find(addr);
if (anItr != gSexyAllocMap.end())
gSexyAllocMap.erase(anItr);
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SexyDumpUnfreed()
{
if (!gSexyAllocMapValid)
return;
AutoCrit aCrit(gSexyAllocMap.mCrit);
SexyAllocMap::iterator i;
int totalSize = 0;
char buf[8192];
#ifdef SEXY_DUMP_LEAKED_MEM
char hex_dump[1024];
char ascii_dump[1024];
int count = 0;
int index = 0;
#endif
FILE* f = fopen("mem_leaks.txt", "wt");
if (!f)
return;
time_t aTime = time(NULL);
sprintf(buf, "Memory Leak Report for %s\n", asctime(localtime(&aTime)));
fprintf(f, buf);
OutputDebugString("\n");
OutputDebugString(buf);
for(i = gSexyAllocMap.begin(); i != gSexyAllocMap.end(); i++)
{
sprintf(buf, "%s(%d) : Leak %d byte%s\n", i->second.file, i->second.line, i->second.size,i->second.size>1?"s":"");
OutputDebugString(buf);
fprintf(f, buf);
#ifdef SEXY_DUMP_LEAKED_MEM
unsigned char* data = (unsigned char*)i->first;
for (index = 0; index < i->second.size; index++)
{
unsigned char _c = *data;
if (count == 0)
sprintf(hex_dump, "\t%02X ", _c);
else
sprintf(hex_dump, "%s%02X ", hex_dump, _c);
if ((_c < 32) || (_c > 126))
_c = '.';
if (count == 7)
sprintf(ascii_dump, "%s%c ", ascii_dump, _c);
else
sprintf(ascii_dump, "%s%c", count == 0 ? "\t" : ascii_dump, _c);
if (++count == 16)
{
count = 0;
sprintf(buf, "%s\t%s\n", hex_dump, ascii_dump);
fprintf(f, buf);
memset((void*)hex_dump, 0, 1024);
memset((void*)ascii_dump, 0, 1024);
}
data++;
}
if (count != 0)
{
fprintf(f, hex_dump);
for (index = 0; index < 16 - count; index++)
fprintf(f, "\t");
fprintf(f, ascii_dump);
for (index = 0; index < 16 - count; index++)
fprintf(f, ".");
}
count = 0;
fprintf(f, "\n\n");
memset((void*)hex_dump, 0, 1024);
memset((void*)ascii_dump, 0, 1024);
#endif // SEXY_DUMP_LEAKED_MEM
totalSize += i->second.size;
}
sprintf(buf, "-----------------------------------------------------------\n");
fprintf(f, buf);
OutputDebugString(buf);
sprintf(buf, "Total Unfreed: %d bytes (%dKB)\n\n", totalSize, totalSize / 1024);
OutputDebugString(buf);
fprintf(f, buf);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void OutputDebug(const SexyChar* fmt ...)
{
va_list argList;
va_start(argList, fmt);
std::string result = SexyStringToStringFast(vformat(fmt, argList));
va_end(argList);
OutputDebugStringA(result.c_str());
}