39#define BLOCXX_MEMTRACER_CPP_INCLUDE_GUARD_
40#include "blocxx/BLOCXX_config.h"
41#ifdef BLOCXX_DEBUG_MEMORY
50#ifdef BLOCXX_HAVE_UNISTD_H
54#define BLOCXX_MEM_SIG 0xaaaaaaaa
55#define BLOCXX_FREE_MEM_SIG 0xbbbbbbbb
62class MemTracerAllocator
65 typedef std::size_t size_type;
66 typedef std::ptrdiff_t difference_type;
68 typedef value_type* pointer;
69 typedef const value_type* const_pointer;
70 typedef value_type& reference;
71 typedef const value_type& const_reference;
72 template <
class U>
struct rebind
74 typedef MemTracerAllocator<U> other;
77 MemTracerAllocator()
throw() {}
78 template <
class U> MemTracerAllocator(
const MemTracerAllocator<U>& other)
throw() {}
79 pointer address(reference r)
const {
return &r; }
80 const_pointer address(const_reference r)
const {
return &r; }
81 pointer allocate(size_type n, const_pointer hint = 0)
83 return static_cast<pointer
>(::malloc(n));
85 void deallocate(pointer p, size_type n)
89 size_type max_size()
const throw() {
return static_cast<size_type
>(-1); }
90 void construct(pointer p, const_reference val) {
new(p) value_type(val); }
91 void destroy(pointer p) { p->~value_type(); }
97static const char*
const noFile =
"<no file>";
104 Entry (
char const * file,
int line,
size_t sz)
105 :
m_file(file), m_line(line), m_size(sz), m_isDeleted(
false) {}
107 :
m_file(NULL), m_line(-1), m_size(0), m_isDeleted(
false) {}
108 char const* getFile()
const {
return m_file; }
109 int getLine()
const {
return m_line; }
110 size_t getSize()
const {
return m_size; }
111 void setDeleted() { m_isDeleted =
true; }
112 bool isDeleted() {
return m_isDeleted; }
123 Lock(MemTracer & tracer) : m_tracer(tracer) { m_tracer.lock (); }
138 typedef MemTracerAllocator<std::pair<void* const, Entry> > alloc_t;
139 typedef std::map<void*, Entry, std::less<void*>, alloc_t > map_t;
140 typedef map_t::iterator iterator;
145 void add(
void* p,
char const* file,
int line,
size_t sz);
146 void* remove(
void * p);
148 Entry getEntry(
void* idx);
149 void printEntry(
void* p);
152 void lock() { m_lockCount++; }
153 void unlock() { m_lockCount--; }
159static Mutex* memguard = NULL;
160static MemTracer* MemoryTracer = 0;
161static bool _shuttingDown =
false;
162static bool noFree =
false;
163static bool aggressive =
false;
164static bool disabled =
false;
169 _shuttingDown =
true;
170 if (MemoryTracer != 0)
172 fprintf(stderr,
"*******************************************************************************\n");
173 fprintf(stderr,
"* D U M P I N G M E M O R Y\n");
174 fprintf(stderr,
"*******************************************************************************\n");
175 MemoryTracer->dump();
176 fprintf(stderr,
"-------------------------------------------------------------------------------\n");
177 fprintf(stderr,
"- D O N E D U M P I N G M E M O R Y\n");
178 fprintf(stderr,
"-------------------------------------------------------------------------------\n");
182 fprintf(stderr, BLOCXX_PACKAGE_NAME
": MemoryTracer object does not exist\n");
185static bool owInternal =
false;
186static bool initialized =
false;
192 if (getenv(
"BLOCXX_MEM_DISABLE") && getenv(
"BLOCXX_MEM_DISABLE")[0] ==
'1')
196 if (getenv(
"BLOCXX_MEM_NOFREE") && getenv(
"BLOCXX_MEM_NOFREE")[0] ==
'1')
200 if (getenv(
"BLOCXX_MEM_AGGRESSIVE") && getenv(
"BLOCXX_MEM_AGGRESSIVE")[0] ==
'1')
203 fprintf(stderr,
"MemTracer running in aggressive mode.\n");
218 memguard =
new Mutex;
221 if (MemoryTracer == 0)
223 atexit(myAtExitFunction);
224 MemoryTracer =
new MemTracer;
232 if (MemoryTracer != 0)
234 MemoryTracer->dump();
238 fprintf(stderr, BLOCXX_PACKAGE_NAME
": MemoryTracer object does not exist\n");
242MemTracer::MemTracer() : m_lockCount (0)
246MemTracer::~MemTracer()
260checkSigs(
void* p,
size_t sz)
264 unsigned long* plong = (
unsigned long*)((
char*)p - 4);
265 if (*plong != BLOCXX_MEM_SIG)
267 fprintf(stderr,
"UNDERRUN: Beginning boundary problem. "
268 "Sig is %x\n", (
unsigned int)*plong);
269 MemoryTracer->printEntry(p);
272 plong = (
unsigned long*)((
char*)p + sz);
273 if (*plong != BLOCXX_MEM_SIG)
275 fprintf(stderr,
"OVERRUN: Ending boundary problem. "
276 "Sig is %x\n", (
unsigned int)*plong);
277 MemoryTracer->printEntry(p);
281 return (
void*)((
char*)p - 4);
285checkAndSwitchSigs(
void* p,
size_t sz)
289 unsigned long* plong = (
unsigned long*)((
char*)p - 4);
290 if (*plong != BLOCXX_MEM_SIG)
292 fprintf(stderr,
"UNDERRUN: Beginning boundary problem. "
293 "Sig is %x\n", (
unsigned int)*plong);
296 *plong = BLOCXX_FREE_MEM_SIG;
297 plong = (
unsigned long*)((
char*)p + sz);
298 if (*plong != BLOCXX_MEM_SIG)
300 fprintf(stderr,
"OVERRUN: Ending boundary problem. "
301 "Sig is %x\n", (
unsigned int)*plong);
304 *plong = BLOCXX_FREE_MEM_SIG;
305 return (
void*)((
char*)p - 4);
311 for (iterator it = m_map.begin(); it != m_map.end(); ++it)
313 if (!it->second.isDeleted())
315 checkSigs(it->first, it->second.getSize());
321MemTracer::add(
void* p,
char const* file,
int line,
size_t sz)
323 const char* pfile = noFile;
326 pfile = strdup(file);
328 m_map[p] = Entry(pfile, line, sz);
332MemTracer::remove(
void* p)
334 iterator it = m_map.find(p);
335 if (it != m_map.end())
339 if (it->second.isDeleted())
341 fprintf(stderr,
"DOUBLE DELETE (NOFREE): Attempting to double "
342 "delete memory at: %p\n", p);
346 void* ptrToFree = checkAndSwitchSigs(p, it->second.getSize());
347 void* pfile = (
void*) it->second.getFile();
350 it->second.setDeleted();
362 fprintf(stderr,
"Attempting to delete memory not in map: %p\n", p);
365 fprintf(stderr,
"Trying to check beginning signature...\n");
366 unsigned long* plong = (
unsigned long*)((
char*)p - 4);
367 if (*plong == BLOCXX_MEM_SIG)
369 fprintf(stderr,
"MemTracer is broken\n");
372 if (*plong == BLOCXX_FREE_MEM_SIG)
374 fprintf(stderr,
"DOUBLE DELETE: This memory was previously freed by MemTracer, "
375 "probably double delete\n");
378 fprintf(stderr,
"No signature detected.\n");
380 fprintf(stderr,
"UNKNOWN ADDRESS\n");
386MemTracer::printEntry(
void* p)
388 Entry entry = getEntry(p);
389 fprintf(stderr,
"\tFILE: %s", entry.getFile());
390 fprintf(stderr,
"\tLINE: %d", entry.getLine());
391 fprintf(stderr,
"\tSIZE: %lu",
static_cast<unsigned long>(entry.getSize()));
392 fprintf(stderr,
"\tADDR: %p\n", p);
396MemTracer::getEntry(
void* idx)
399 iterator it = m_map.find(idx);
400 MemTracer::Entry rval;
401 if (it != m_map.end())
413 if (m_map.size() != 0)
415 fprintf(stderr,
"**** %lu MEMORY LEAK(S) DETECTED\n",
static_cast<unsigned long>(m_map.size()));
417 for (iterator it = m_map.begin(); it != m_map.end (); ++it)
419 if (!it->second.isDeleted())
421 fprintf(stderr,
"\tFILE: %s", it->second.getFile());
422 fprintf(stderr,
"\tLINE: %d", it->second.getLine());
423 fprintf(stderr,
"\tSIZE: %lu",
static_cast<unsigned long>(it->second.getSize()));
424 fprintf(stderr,
"\tADDR: %p\n", it->first);
425 total += it->second.getSize();
428 fprintf(stderr,
"***** END MEMORY LEAKS - TOTAL MEMORY LEAKED = %lu\n",
static_cast<unsigned long>(total));
434writeSigs(
void *& p,
size_t size)
436 unsigned long* plong = (
unsigned long*)p;
437 *plong = BLOCXX_MEM_SIG;
438 plong = (
unsigned long*)((
char*)p + size + 4);
439 *plong = BLOCXX_MEM_SIG;
440 p = (
void*)((
char*)p + 4);
442static int internalNewCount = 0;
445doNew(
size_t size,
char const* file,
int line)
451 if (owInternal || disabled)
454 if (internalNewCount > 2 && !disabled)
456 fprintf(stderr,
"INTERNAL NEW called more than twice! "
457 "Possible bug in MemTracer.\n");
460 void* rval = malloc(size);
475 MemoryTracer->checkMap();
477 void* p = malloc(size + 8);
481 perror(
"malloc failed.");
486 assert (MemoryTracer);
487 MemoryTracer->add(p, file, line, size);
502 if (owInternal || disabled)
506 fprintf(stderr,
"INTERNAL DELETE: %p\n", p);
517 MemoryTracer->checkMap();
520 if (MemoryTracer != 0)
522 p = MemoryTracer->remove((
void*)((
char*)p));
526 printf(
"** MemTracer can't remove delete from map: ADDR: %p\n", p);
538 fprintf(stderr,
"delete called\n");
546operator new[](std::size_t size,
char const* file,
int line)
throw(std::bad_alloc)
548 return BLOCXX_NAMESPACE::doNew(size, file, line);
552operator new(std::size_t size,
char const* file,
int line)
throw(std::bad_alloc)
554 return BLOCXX_NAMESPACE::doNew(size, file, line);
558operator new[](std::size_t size)
throw(std::bad_alloc)
560 return BLOCXX_NAMESPACE::doNew(size, NULL, 0);
564operator new(std::size_t size)
throw(std::bad_alloc)
566 return BLOCXX_NAMESPACE::doNew(size, NULL, 0);
569operator delete(
void* p)
571 BLOCXX_NAMESPACE::doDelete(p);
574operator delete[](
void* p)
576 BLOCXX_NAMESPACE::doDelete(p);