summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris+github@qwirx.com>2006-11-13 16:07:36 +0000
committerChris Wilson <chris+github@qwirx.com>2006-11-13 16:07:36 +0000
commitc26856da8e344e7ec94d55f92ed49a09f04c5769 (patch)
treed0b1ac1ad274e27a93844ebb4848584c0c538f58
parentab0b5628af0aaf7851a4ca377a25ed569d4112c2 (diff)
* Track memory leaks in allocations via the standard libraries, and
avoid malloc/delete mismatches, by overriding standard new operator. * Added another global enable flag to memleak finder, which is used to mark the end of static allocations and the start of dynamic code, since the memory leak detection is done before cleanup of static objects. * Added a public guard class, to allow safe scoped disabling of memory leak detection. * Added InternalAllocGuard to protect against recursive loops when allocating memory inside the memory leak checker. (refs #3)
-rw-r--r--lib/common/DebugMemLeakFinder.cpp139
-rw-r--r--lib/common/MemLeakFinder.h16
2 files changed, 133 insertions, 22 deletions
diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp
index 71665102..64ea0bd3 100644
--- a/lib/common/DebugMemLeakFinder.cpp
+++ b/lib/common/DebugMemLeakFinder.cpp
@@ -25,6 +25,7 @@
#include <string.h>
#include <set>
+static bool memleakfinder_initialised = false;
bool memleakfinder_global_enable = false;
typedef struct
@@ -58,8 +59,38 @@ namespace
size_t sNotLeaksPreNum = 0;
}
+void memleakfinder_init()
+{
+ ASSERT(!memleakfinder_initialised);
+ memleakfinder_initialised = true;
+}
+
+MemLeakSuppressionGuard::MemLeakSuppressionGuard()
+{
+ ASSERT(memleakfinder_global_enable);
+ memleakfinder_global_enable = false;
+}
+
+MemLeakSuppressionGuard::~MemLeakSuppressionGuard()
+{
+ ASSERT(!memleakfinder_global_enable);
+ memleakfinder_global_enable = true;
+}
+
+// these functions may well allocate memory, which we don't want to track.
+static int sInternalAllocDepth = 0;
+
+class InternalAllocGuard
+{
+ public:
+ InternalAllocGuard () { sInternalAllocDepth++; }
+ ~InternalAllocGuard() { sInternalAllocDepth--; }
+};
+
void memleakfinder_malloc_add_block(void *b, size_t size, const char *file, int line)
{
+ InternalAllocGuard guard;
+
if(b != 0)
{
MallocBlockInfo i;
@@ -75,11 +106,13 @@ void memleakfinder_malloc_add_block(void *b, size_t size, const char *file, int
}
}
-
void *memleakfinder_malloc(size_t size, const char *file, int line)
{
+ InternalAllocGuard guard;
+
void *b = ::malloc(size);
if(!memleakfinder_global_enable) return b;
+ if(!memleakfinder_initialised) return b;
memleakfinder_malloc_add_block(b, size, file, line);
@@ -89,7 +122,9 @@ void *memleakfinder_malloc(size_t size, const char *file, int line)
void *memleakfinder_realloc(void *ptr, size_t size)
{
- if(!memleakfinder_global_enable)
+ InternalAllocGuard guard;
+
+ if(!memleakfinder_global_enable || !memleakfinder_initialised)
{
return ::realloc(ptr, size);
}
@@ -133,7 +168,9 @@ void *memleakfinder_realloc(void *ptr, size_t size)
void memleakfinder_free(void *ptr)
{
- if(memleakfinder_global_enable)
+ InternalAllocGuard guard;
+
+ if(memleakfinder_global_enable && memleakfinder_initialised)
{
// Check it's been allocated
std::map<void *, MallocBlockInfo>::iterator i(sMallocBlocks.find(ptr));
@@ -143,7 +180,7 @@ void memleakfinder_free(void *ptr)
}
else
{
- TRACE1("Block %x freed, but not known. Error? Or allocated in startup static allocation?\n", ptr);
+ TRACE1("Block %p freed, but not known. Error? Or allocated in startup static allocation?\n", ptr);
}
if(sTrackMallocInSection)
@@ -160,24 +197,34 @@ void memleakfinder_free(void *ptr)
void memleakfinder_notaleak_insert_pre()
{
+ InternalAllocGuard guard;
+
if(!memleakfinder_global_enable) return;
+ if(!memleakfinder_initialised) return;
+
for(size_t l = 0; l < sNotLeaksPreNum; l++)
{
sNotLeaks.insert(sNotLeaksPre[l]);
}
+
sNotLeaksPreNum = 0;
}
bool is_leak(void *ptr)
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
memleakfinder_notaleak_insert_pre();
return sNotLeaks.find(ptr) == sNotLeaks.end();
}
void memleakfinder_notaleak(void *ptr)
{
+ InternalAllocGuard guard;
+
memleakfinder_notaleak_insert_pre();
- if(memleakfinder_global_enable)
+ if(memleakfinder_global_enable && memleakfinder_initialised)
{
sNotLeaks.insert(ptr);
}
@@ -206,6 +253,9 @@ void memleakfinder_notaleak(void *ptr)
// start monitoring a section of code
void memleakfinder_startsectionmonitor()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
sTrackMallocInSection = true;
sSectionMallocBlocks.clear();
sTrackObjectsInSection = true;
@@ -215,6 +265,10 @@ void memleakfinder_startsectionmonitor()
// trace all blocks allocated and still allocated since memleakfinder_startsectionmonitor() called
void memleakfinder_traceblocksinsection()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
+
std::set<void *>::iterator s(sSectionMallocBlocks.begin());
for(; s != sSectionMallocBlocks.end(); ++s)
{
@@ -225,17 +279,21 @@ void memleakfinder_traceblocksinsection()
}
else
{
- TRACE4("Block 0x%08p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
+ TRACE4("Block %p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
}
}
for(std::map<void *, ObjectInfo>::const_iterator i(sSectionObjectBlocks.begin()); i != sSectionObjectBlocks.end(); ++i)
{
- TRACE5("Object%s 0x%08p size %d allocated at %s:%d\n", i->second.array?" []":"", i->first, i->second.size, i->second.file, i->second.line);
+ TRACE5("Object%s %p size %d allocated at %s:%d\n", i->second.array?" []":"", i->first, i->second.size, i->second.file, i->second.line);
}
}
int memleakfinder_numleaks()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
+
int n = 0;
for(std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
@@ -245,6 +303,7 @@ int memleakfinder_numleaks()
for(std::map<void *, ObjectInfo>::const_iterator i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i)
{
+ const ObjectInfo& rInfo = i->second;
if(is_leak(i->first)) ++n;
}
@@ -253,6 +312,8 @@ int memleakfinder_numleaks()
void memleakfinder_reportleaks_file(FILE *file)
{
+ InternalAllocGuard guard;
+
for(std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
{
if(is_leak(i->first)) ::fprintf(file, "Block 0x%p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
@@ -265,12 +326,16 @@ void memleakfinder_reportleaks_file(FILE *file)
void memleakfinder_reportleaks()
{
+ InternalAllocGuard guard;
+
// report to stdout
memleakfinder_reportleaks_file(stdout);
}
void memleakfinder_reportleaks_appendfile(const char *filename, const char *markertext)
{
+ InternalAllocGuard guard;
+
FILE *file = ::fopen(filename, "a");
if(file != 0)
{
@@ -317,7 +382,10 @@ void memleakfinder_setup_exit_report(const char *filename, const char *markertex
void add_object_block(void *block, size_t size, const char *file, int line, bool array)
{
+ InternalAllocGuard guard;
+
if(!memleakfinder_global_enable) return;
+ if(!memleakfinder_initialised) return;
if(block != 0)
{
@@ -337,7 +405,10 @@ void add_object_block(void *block, size_t size, const char *file, int line, bool
void remove_object_block(void *block)
{
+ InternalAllocGuard guard;
+
if(!memleakfinder_global_enable) return;
+ if(!memleakfinder_initialised) return;
std::map<void *, ObjectInfo>::iterator i(sObjectBlocks.find(block));
if(i != sObjectBlocks.end())
@@ -357,34 +428,64 @@ void remove_object_block(void *block)
// If it's not in the list, just ignore it, as lots of stuff goes this way...
}
-void *operator new(size_t size, const char *file, int line)
+static void *internal_new(size_t size, const char *file, int line)
{
- void *r = ::malloc(size);
- add_object_block(r, size, file, line, false);
- //TRACE4("new(), %d, %s, %d, %08x\n", size, file, line, r);
+ void *r;
+
+ {
+ InternalAllocGuard guard;
+ r = ::malloc(size);
+ }
+
+ if (sInternalAllocDepth == 0)
+ {
+ InternalAllocGuard guard;
+ add_object_block(r, size, file, line, false);
+ //TRACE4("new(), %d, %s, %d, %08x\n", size, file, line, r);
+ }
+
return r;
}
+void *operator new(size_t size, const char *file, int line)
+{
+ return internal_new(size, file, line);
+}
+
void *operator new[](size_t size, const char *file, int line)
{
- void *r = ::malloc(size);
- add_object_block(r, size, file, line, true);
- //TRACE4("new[](), %d, %s, %d, %08x\n", size, file, line, r);
- return r;
+ return internal_new(size, file, line);
}
-void operator delete[](void *ptr) throw ()
+// where there is no doctor... need to override standard new() too
+// http://www.relisoft.com/book/tech/9new.html
+void *operator new(size_t size)
+{
+ return internal_new(size, "standard libraries", 0);
+}
+
+void *operator new[](size_t size)
+{
+ return internal_new(size, "standard libraries", 0);
+}
+
+void internal_delete(void *ptr)
{
+ InternalAllocGuard guard;
+
::free(ptr);
remove_object_block(ptr);
//TRACE1("delete[]() called, %08x\n", ptr);
}
+void operator delete[](void *ptr) throw ()
+{
+ internal_delete(ptr);
+}
+
void operator delete(void *ptr) throw ()
{
- ::free(ptr);
- remove_object_block(ptr);
- //TRACE1("delete() called, %08x\n", ptr);
+ internal_delete(ptr);
}
#endif // NDEBUG
diff --git a/lib/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h
index f5887dac..f47a38aa 100644
--- a/lib/common/MemLeakFinder.h
+++ b/lib/common/MemLeakFinder.h
@@ -20,6 +20,13 @@
// global enable flag
extern bool memleakfinder_global_enable;
+class MemLeakSuppressionGuard
+{
+ public:
+ MemLeakSuppressionGuard();
+ ~MemLeakSuppressionGuard();
+};
+
extern "C"
{
void *memleakfinder_malloc(size_t size, const char *file, int line);
@@ -27,6 +34,8 @@ extern "C"
void memleakfinder_free(void *ptr);
}
+void memleakfinder_init();
+
int memleakfinder_numleaks();
void memleakfinder_reportleaks();
@@ -41,10 +50,12 @@ void memleakfinder_traceblocksinsection();
void memleakfinder_notaleak(void *ptr);
-void *operator new(size_t size, const char *file, int line);
+void *operator new (size_t size, const char *file, int line);
void *operator new[](size_t size, const char *file, int line);
+void *operator new (size_t size);
+void *operator new[](size_t size);
-void operator delete(void *ptr) throw ();
+void operator delete (void *ptr) throw ();
void operator delete[](void *ptr) throw ();
// define the malloc functions now, if required
@@ -55,6 +66,5 @@ void operator delete[](void *ptr) throw ();
#define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
#endif
-
#endif // MEMLEAKFINDER__H