[Box Backup-commit] COMMIT r1159 - box/chris/merge/lib/common
boxbackup-dev@fluffy.co.uk
boxbackup-dev@fluffy.co.uk
Mon, 13 Nov 2006 16:07:36 +0000
Author: chris
Date: 2006-11-13 16:07:36 +0000 (Mon, 13 Nov 2006)
New Revision: 1159
Modified:
box/chris/merge/lib/common/DebugMemLeakFinder.cpp
box/chris/merge/lib/common/MemLeakFinder.h
Log:
* 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)
Modified: box/chris/merge/lib/common/DebugMemLeakFinder.cpp
===================================================================
--- box/chris/merge/lib/common/DebugMemLeakFinder.cpp 2006-11-13 16:00:52 UTC (rev 1158)
+++ box/chris/merge/lib/common/DebugMemLeakFinder.cpp 2006-11-13 16:07:36 UTC (rev 1159)
@@ -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 @@
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(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_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_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 @@
}
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_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 @@
// start monitoring a section of code
void memleakfinder_startsectionmonitor()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
sTrackMallocInSection = true;
sSectionMallocBlocks.clear();
sTrackObjectsInSection = true;
@@ -215,6 +265,10 @@
// 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 @@
}
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 @@
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 @@
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()
{
+ 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 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 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 @@
// 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
Modified: box/chris/merge/lib/common/MemLeakFinder.h
===================================================================
--- box/chris/merge/lib/common/MemLeakFinder.h 2006-11-13 16:00:52 UTC (rev 1158)
+++ box/chris/merge/lib/common/MemLeakFinder.h 2006-11-13 16:07:36 UTC (rev 1159)
@@ -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 @@
void memleakfinder_free(void *ptr);
}
+void memleakfinder_init();
+
int memleakfinder_numleaks();
void memleakfinder_reportleaks();
@@ -41,10 +50,12 @@
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 @@
#define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
#endif
-
#endif // MEMLEAKFINDER__H