ultimatepp/uppsrc/Core/heapdbg.cpp
cxl 8ebdcbb0d5 uppsrc: NAMESPACE_UPP / END_UPP_NAMESPACE removed
git-svn-id: svn://ultimatepp.org/upp/trunk@10186 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-08-26 17:15:30 +00:00

263 lines
5.1 KiB
C++

#include "Core.h"
// #define LOGAF
#if (defined(TESTLEAKS) || defined(HEAPDBG)) && defined(COMPILER_GCC) && defined(UPP_HEAP)
int sMemDiagInitCount;
#endif
namespace Upp {
#if defined(UPP_HEAP)
#include "HeapImp.h"
#if defined(HEAPDBG)
extern bool PanicMode;
void HeapPanic(const char *text, void *pos, int size);
static StaticCriticalSection sHeapLock2;
struct alignas(16) DbgBlkHeader {
size_t size;
DbgBlkHeader *prev;
DbgBlkHeader *next;
dword serial;
void LinkSelf() {
next = prev = this;
}
void Unlink() {
prev->next = next;
next->prev = prev;
}
void Insert(DbgBlkHeader *lnk) {
lnk->prev = this;
lnk->next = next;
next->prev = lnk;
next = lnk;
}
};
static const char *DbgFormat(char *b, DbgBlkHeader *p)
{
sprintf(b, "--memory-breakpoint__ %u ", (dword)~(p->serial ^ (uintptr_t)p));
return b;
}
static void DbgHeapPanic(const char *text, DbgBlkHeader *p)
{
char h[256];
char b[100];
strcpy(h, text);
strcat(h, DbgFormat(b, p));
HeapPanic(h, p + 1, (int)(uintptr_t)p->size);
}
static DbgBlkHeader dbg_live = { 0, &dbg_live, &dbg_live, 0 };
static dword s_allocbreakpoint;
static thread__ dword s_ignoreleaks;
void MemoryIgnoreLeaksBegin()
{
CriticalSection::Lock __(sHeapLock2);
s_ignoreleaks++;
}
void MemoryIgnoreLeaksEnd()
{
CriticalSection::Lock __(sHeapLock2);
s_ignoreleaks--;
}
void MemoryBreakpoint(dword serial)
{
s_allocbreakpoint = serial;
}
void *MemoryAlloc_(size_t size);
void *MemoryAlloc(size_t size)
{
if(PanicMode)
return malloc(size);
#ifdef _MULTITHREADED
sHeapLock2.Enter();
#endif
static dword serial_number = 0;
DbgBlkHeader *p = (DbgBlkHeader *)MemoryAlloc_(sizeof(DbgBlkHeader) + size + sizeof(dword));
#if (defined(TESTLEAKS) || defined(HEAPDBG)) && defined(COMPILER_GCC) && defined(UPP_HEAP)
p->serial = sMemDiagInitCount == 0 || s_ignoreleaks ? 0 : ~ ++serial_number ^ (dword)(uintptr_t) p;
#else
p->serial = s_ignoreleaks ? 0 : ~ ++serial_number ^ (dword)(uintptr_t) p;
#endif
p->size = size;
if(s_allocbreakpoint && s_allocbreakpoint == serial_number)
__BREAK__;
dbg_live.Insert(p);
Poke32le((byte *)(p + 1) + p->size, p->serial);
#ifdef _MULTITHREADED
sHeapLock2.Leave();
#endif
#ifdef LOGAF
char h[200];
sprintf(h, "ALLOCATED %d at %p - %p", size, p + 1, (byte *)(p + 1) + size);
DLOG(h);
#endif
return p + 1;
}
void *MemoryAllocSz(size_t& size)
{
size = (size + 15) & ~((size_t)15);
return MemoryAlloc(size);
}
void MemoryFree_(void *ptr);
void MemoryFree(void *ptr)
{
#ifdef LOGAF
char h[200];
sprintf(h, "FREE %p", ptr);
DLOG(h);
#endif
if(PanicMode)
return;
if(!ptr) return;
#ifdef _MULTITHREADED
CriticalSection::Lock __(sHeapLock2);
#endif
DbgBlkHeader *p = (DbgBlkHeader *)ptr - 1;
if((dword)Peek32le((byte *)(p + 1) + p->size) != p->serial) {
sHeapLock2.Leave();
DbgHeapPanic("Heap is corrupted ", p);
}
p->Unlink();
MemoryFree_(p);
}
size_t GetMemoryBlockSize_(void *ptr);
size_t GetMemoryBlockSize(void *ptr)
{
if(!ptr) return 0;
return ((DbgBlkHeader *)ptr - 1)->size;
}
bool TryRealloc(void *ptr, size_t newsize)
{
return false;
}
void *MemoryAlloc32() { return MemoryAlloc(32); }
void MemoryFree32(void *ptr) { return MemoryFree(ptr); }
void *MemoryAlloc48() { return MemoryAlloc(48); }
void MemoryFree48(void *ptr) { return MemoryFree(ptr); }
void MemoryCheckDebug()
{
MemoryCheck();
CriticalSection::Lock __(sHeapLock2);
DbgBlkHeader *p = dbg_live.next;
while(p != &dbg_live) {
if((dword)Peek32le((byte *)(p + 1) + p->size) != p->serial) {
sHeapLock2.Leave();
DbgHeapPanic("HEAP CHECK: Heap is corrupted ", p);
}
p = p->next;
}
while(p != &dbg_live);
}
void MemoryDumpLeaks()
{
if(PanicMode)
return;
#ifndef PLATFORM_POSIX
if(s_ignoreleaks)
Panic("Ignore leaks Begin/End mismatch!");
#endif
MemoryCheckDebug();
DbgBlkHeader *p = dbg_live.next;
bool leaks = false;
int n = 0;
while(p != &dbg_live) {
if(p->serial) {
if(!leaks)
VppLog() << "\n\nHeap leaks detected:\n";
leaks = true;
char b[100];
DbgFormat(b, p);
VppLog() << '\n' << b << ": ";
HexDump(VppLog(), p + 1, (int)(uintptr_t)p->size, 64);
if(++n > 16) {
while(p->next != &dbg_live && n < 10000000) {
++n;
p = p->next;
}
sprintf(b, "%d", n);
VppLog() << "\n*** TOO MANY LEAKS (" << n << ") TO LIST THEM ALL\n";
break;
}
}
p = p->next;
}
if(!leaks)
return;
#ifdef PLATFORM_WIN32
MessageBox(::GetActiveWindow(),
"Heap leaks detected !",
"Warning",
MB_ICONSTOP|MB_OK|MB_APPLMODAL);
#else
if(!IsPanicMode())
Panic("Heap leaks detected!");
#endif
Heap::AuxFinalCheck();
}
#ifdef COMPILER_MSC
#pragma warning(disable: 4074)
#pragma init_seg(compiler)
EXITBLOCK { MemoryDumpLeaks(); }
#endif
#ifdef COMPILER_GCC
void MemoryInitDiagnostics()
{
}
#endif
#endif
#endif
}
#if (defined(TESTLEAKS) || defined(HEAPDBG)) && defined(COMPILER_GCC) && defined(UPP_HEAP)
MemDiagCls::MemDiagCls()
{
if(sMemDiagInitCount++ == 0)
UPP::MemoryInitDiagnostics();
}
MemDiagCls::~MemDiagCls()
{
if(--sMemDiagInitCount == 0)
UPP::MemoryDumpLeaks();
}
static const MemDiagCls sMemDiagHelper __attribute__ ((init_priority (101)));
#endif