00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00036 #define OW_MEMTRACER_CPP_INCLUDE_GUARD_
00037 #include "OW_config.h"
00038 #ifdef OW_DEBUG_MEMORY
00039 #include "OW_MemTracer.hpp"
00040 #include "OW_Mutex.hpp"
00041 #include <map>
00042 #include <cstdio>
00043 #include <cstdlib>
00044 #include <cassert>
00045 #include <errno.h>
00046
00047 #if !defined(OW_WIN32)
00048 #include <unistd.h>
00049 #endif
00050
00051 #define OW_MEM_SIG 0xaaaaaaaa
00052 #define OW_FREE_MEM_SIG 0xbbbbbbbb
00053
00054 namespace OW_NAMESPACE
00055 {
00056
00057
00058 template <typename T>
00059 class MemTracerAllocator
00060 {
00061 public:
00062 typedef std::size_t size_type;
00063 typedef std::ptrdiff_t difference_type;
00064 typedef T value_type;
00065 typedef value_type* pointer;
00066 typedef const value_type* const_pointer;
00067 typedef value_type& reference;
00068 typedef const value_type& const_reference;
00069 template <class U> struct rebind
00070 {
00071 typedef MemTracerAllocator<U> other;
00072 };
00073
00074 MemTracerAllocator() throw() {}
00075 template <class U> MemTracerAllocator(const MemTracerAllocator<U>& other) throw() {}
00076 pointer address(reference r) const { return &r; }
00077 const_pointer address(const_reference r) const { return &r; }
00078 pointer allocate(size_type n, const_pointer hint = 0)
00079 {
00080 return static_cast<pointer>(::malloc(n));
00081 }
00082 void deallocate(pointer p, size_type n)
00083 {
00084 ::free(p);
00085 }
00086 size_type max_size() const throw() { return static_cast<size_type>(-1); }
00087 void construct(pointer p, const_reference val) { new(p) value_type(val); }
00088 void destroy(pointer p) { p->~value_type(); }
00089
00090 };
00091
00092
00093
00094 static const char* const noFile = "<no file>";
00095 class MemTracer
00096 {
00097 public:
00098 class Entry
00099 {
00100 public:
00101 Entry (char const * file, int line, size_t sz)
00102 : m_file(file), m_line(line), m_size(sz), m_isDeleted(false) {}
00103 Entry()
00104 : m_file(NULL), m_line(-1), m_size(0), m_isDeleted(false) {}
00105 char const* getFile() const { return m_file; }
00106 int getLine() const { return m_line; }
00107 size_t getSize() const { return m_size; }
00108 void setDeleted() { m_isDeleted = true; }
00109 bool isDeleted() { return m_isDeleted; }
00110 private:
00111 char const* m_file;
00112 int m_line;
00113 size_t m_size;
00114 bool m_isDeleted;
00115 };
00116 private:
00117 class Lock
00118 {
00119 public:
00120 Lock(MemTracer & tracer) : m_tracer(tracer) { m_tracer.lock (); }
00121 ~Lock()
00122 {
00123 try
00124 {
00125 m_tracer.unlock ();
00126 }
00127 catch (...)
00128 {
00129
00130 }
00131 }
00132 private:
00133 MemTracer& m_tracer;
00134 };
00135 typedef std::map<void*, Entry, std::less<void*>, MemTracerAllocator<Entry> >::iterator iterator;
00136 friend class Lock;
00137 public:
00138 MemTracer();
00139 ~MemTracer();
00140 void add(void* p, char const* file, int line, size_t sz);
00141 void* remove(void * p);
00142 void dump();
00143 Entry getEntry(void* idx);
00144 void printEntry(void* p);
00145 void checkMap();
00146 private:
00147 void lock() { m_lockCount++; }
00148 void unlock() { m_lockCount--; }
00149 private:
00150 std::map<void*, Entry, std::less<void*>, MemTracerAllocator<Entry> > m_map;
00151 int m_lockCount;
00152 };
00153
00154 static Mutex* memguard = NULL;
00155 static MemTracer* MemoryTracer = 0;
00156 static bool _shuttingDown = false;
00157 static bool noFree = false;
00158 static bool aggressive = false;
00159 static bool disabled = false;
00161 void
00162 myAtExitFunction()
00163 {
00164 _shuttingDown = true;
00165 if (MemoryTracer != 0)
00166 {
00167 fprintf(stderr, "*******************************************************************************\n");
00168 fprintf(stderr, "* D U M P I N G M E M O R Y\n");
00169 fprintf(stderr, "*******************************************************************************\n");
00170 MemoryTracer->dump();
00171 fprintf(stderr, "-------------------------------------------------------------------------------\n");
00172 fprintf(stderr, "- D O N E D U M P I N G M E M O R Y\n");
00173 fprintf(stderr, "-------------------------------------------------------------------------------\n");
00174 }
00175 else
00176 {
00177 fprintf(stderr, "OpenWBEM: MemoryTracer object does not exist\n");
00178 }
00179 }
00180 static bool owInternal = false;
00181 static bool initialized = false;
00182 void
00183 processEnv()
00184 {
00185 if (!initialized)
00186 {
00187 if (getenv("OW_MEM_DISABLE") && getenv("OW_MEM_DISABLE")[0] == '1')
00188 {
00189 disabled = true;
00190 }
00191 if (getenv("OW_MEM_NOFREE") && getenv("OW_MEM_NOFREE")[0] == '1')
00192 {
00193 noFree = true;
00194 }
00195 if (getenv("OW_MEM_AGGRESSIVE") && getenv("OW_MEM_AGGRESSIVE")[0] == '1')
00196 {
00197 aggressive = true;
00198 fprintf(stderr, "MemTracer running in aggressive mode.\n");
00199 }
00200 initialized = true;
00201 }
00202 }
00204 void
00205 allocMemTracer()
00206 {
00207 owInternal = true;
00208 processEnv();
00209 if (!disabled)
00210 {
00211 if (memguard == 0)
00212 {
00213 memguard = new Mutex;
00214 memguard->acquire();
00215 }
00216 if (MemoryTracer == 0)
00217 {
00218 atexit(myAtExitFunction);
00219 MemoryTracer = new MemTracer;
00220 }
00221 }
00222 owInternal = false;
00223 }
00225 void DumpMemory()
00226 {
00227 if (MemoryTracer != 0)
00228 {
00229 MemoryTracer->dump();
00230 }
00231 else
00232 {
00233 fprintf(stderr, "OpenWBEM: MemoryTracer object does not exist\n");
00234 }
00235 }
00237 MemTracer::MemTracer() : m_lockCount (0)
00238 {
00239 }
00241 MemTracer::~MemTracer()
00242 {
00243 try
00244 {
00245 dump();
00246 }
00247 catch (...)
00248 {
00249
00250 }
00251 }
00252
00254 static void*
00255 checkSigs(void* p, size_t sz)
00256 {
00257 assert(sz);
00258 assert(p);
00259 unsigned long* plong = (unsigned long*)((char*)p - 4);
00260 if (*plong != OW_MEM_SIG)
00261 {
00262 fprintf(stderr, "UNDERRUN: Beginning boundary problem. "
00263 "Sig is %x\n", (unsigned int)*plong);
00264 MemoryTracer->printEntry(p);
00265 assert(0);
00266 }
00267 plong = (unsigned long*)((char*)p + sz);
00268 if (*plong != OW_MEM_SIG)
00269 {
00270 fprintf(stderr, "OVERRUN: Ending boundary problem. "
00271 "Sig is %x\n", (unsigned int)*plong);
00272 MemoryTracer->printEntry(p);
00273 fflush(stderr);
00274 assert(0);
00275 }
00276 return (void*)((char*)p - 4);
00277 }
00279 static void*
00280 checkAndSwitchSigs(void* p, size_t sz)
00281 {
00282 assert(sz);
00283 assert(p);
00284 unsigned long* plong = (unsigned long*)((char*)p - 4);
00285 if (*plong != OW_MEM_SIG)
00286 {
00287 fprintf(stderr, "UNDERRUN: Beginning boundary problem. "
00288 "Sig is %x\n", (unsigned int)*plong);
00289 assert(0);
00290 }
00291 *plong = OW_FREE_MEM_SIG;
00292 plong = (unsigned long*)((char*)p + sz);
00293 if (*plong != OW_MEM_SIG)
00294 {
00295 fprintf(stderr, "OVERRUN: Ending boundary problem. "
00296 "Sig is %x\n", (unsigned int)*plong);
00297 assert(0);
00298 }
00299 *plong = OW_FREE_MEM_SIG;
00300 return (void*)((char*)p - 4);
00301 }
00303 void
00304 MemTracer::checkMap()
00305 {
00306 for (iterator it = m_map.begin(); it != m_map.end(); ++it)
00307 {
00308 if (!it->second.isDeleted())
00309 {
00310 checkSigs(it->first, it->second.getSize());
00311 }
00312 }
00313 }
00315 void
00316 MemTracer::add(void* p, char const* file, int line, size_t sz)
00317 {
00318 const char* pfile = noFile;
00319 if (file)
00320 {
00321 pfile = strdup(file);
00322 }
00323 m_map[p] = Entry(pfile, line, sz);
00324 }
00326 void*
00327 MemTracer::remove(void* p)
00328 {
00329 iterator it = m_map.find(p);
00330 if (it != m_map.end())
00331 {
00332 if (noFree)
00333 {
00334 if (it->second.isDeleted())
00335 {
00336 fprintf(stderr, "DOUBLE DELETE (NOFREE): Attempting to double "
00337 "delete memory at: %p\n", p);
00338 assert(0);
00339 }
00340 }
00341 void* ptrToFree = checkAndSwitchSigs(p, it->second.getSize());
00342 void* pfile = (void*) it->second.getFile();
00343 if (noFree)
00344 {
00345 it->second.setDeleted();
00346 }
00347 else
00348 {
00349 m_map.erase(it);
00350 if (pfile != noFile)
00351 {
00352 free(pfile);
00353 }
00354 }
00355 return ptrToFree;
00356 }
00357 fprintf(stderr, "Attempting to delete memory not in map: %p\n", p);
00358 if (!noFree)
00359 {
00360 fprintf(stderr, "Trying to check beginning signature...\n");
00361 unsigned long* plong = (unsigned long*)((char*)p - 4);
00362 if (*plong == OW_MEM_SIG)
00363 {
00364 fprintf(stderr, "MemTracer is broken\n");
00365 assert(0);
00366 }
00367 if (*plong == OW_FREE_MEM_SIG)
00368 {
00369 fprintf(stderr, "DOUBLE DELETE: This memory was previously freed by MemTracer, "
00370 "probably double delete\n");
00371 assert(0);
00372 }
00373 fprintf(stderr, "No signature detected.\n");
00374 }
00375 fprintf(stderr, "UNKNOWN ADDRESS\n");
00376 assert(0);
00377 return p;
00378 }
00380 void
00381 MemTracer::printEntry(void* p)
00382 {
00383 Entry entry = getEntry(p);
00384 fprintf(stderr, "\tFILE: %s", entry.getFile());
00385 fprintf(stderr, "\tLINE: %d", entry.getLine());
00386 fprintf(stderr, "\tSIZE: %d", entry.getSize());
00387 fprintf(stderr, "\tADDR: %x\n", (unsigned int)p);
00388 }
00390 MemTracer::Entry
00391 MemTracer::getEntry(void* idx)
00392 {
00393 memguard->acquire();
00394 iterator it = m_map.find(idx);
00395 MemTracer::Entry rval;
00396 if (it != m_map.end())
00397 {
00398 rval = it->second;
00399 }
00400 memguard->release();
00401 return rval;
00402 }
00404 void
00405 MemTracer::dump()
00406 {
00407 memguard->acquire();
00408 if (m_map.size() != 0)
00409 {
00410 fprintf(stderr, "**** %d MEMORY LEAK(S) DETECTED\n", m_map.size());
00411 size_t total = 0;
00412 for (iterator it = m_map.begin(); it != m_map.end (); ++it)
00413 {
00414 if (!it->second.isDeleted())
00415 {
00416 fprintf(stderr, "\tFILE: %s", it->second.getFile());
00417 fprintf(stderr, "\tLINE: %d", it->second.getLine());
00418 fprintf(stderr, "\tSIZE: %d", it->second.getSize());
00419 fprintf(stderr, "\tADDR: %x\n", (unsigned int)it->first);
00420 total += it->second.getSize();
00421 }
00422 }
00423 fprintf(stderr, "***** END MEMORY LEAKS - TOTAL MEMORY LEAKED = %d\n", total);
00424 }
00425 memguard->release();
00426 }
00428 static void
00429 writeSigs(void *& p, size_t size)
00430 {
00431 unsigned long* plong = (unsigned long*)p;
00432 *plong = OW_MEM_SIG;
00433 plong = (unsigned long*)((char*)p + size + 4);
00434 *plong = OW_MEM_SIG;
00435 p = (void*)((char*)p + 4);
00436 }
00437 static int internalNewCount = 0;
00439 static void*
00440 doNew(size_t size, char const* file, int line)
00441 {
00442 if (memguard)
00443 {
00444 memguard->acquire();
00445 }
00446 if (owInternal || disabled)
00447 {
00448 ++internalNewCount;
00449 if (internalNewCount > 2 && !disabled)
00450 {
00451 fprintf(stderr, "INTERNAL NEW called more than twice! "
00452 "Possible bug in MemTracer.\n");
00453 assert(0);
00454 }
00455 void* rval = malloc(size);
00456 if (memguard)
00457 {
00458 memguard->release();
00459 }
00460 --internalNewCount;
00461 return rval;
00462 }
00463 allocMemTracer();
00464 if (disabled)
00465 {
00466 return malloc(size);
00467 }
00468 if (aggressive)
00469 {
00470 MemoryTracer->checkMap();
00471 }
00472 void* p = malloc(size + 8);
00473 if (!p)
00474 {
00475 memguard->release();
00476 perror("malloc failed.");
00477 exit(errno);
00478 }
00479 writeSigs(p, size);
00480 owInternal = true;
00481 assert (MemoryTracer);
00482 MemoryTracer->add(p, file, line, size);
00483 owInternal = false;
00484 memguard->release();
00485 return p;
00486 }
00488 static void
00489 doDelete(void* p)
00490 {
00491 if (p)
00492 {
00493 if (memguard)
00494 {
00495 memguard->acquire();
00496 }
00497 if (owInternal || disabled)
00498 {
00499 if (!disabled)
00500 {
00501 fprintf(stderr, "INTERNAL DELETE: %p\n", p);
00502 }
00503 free(p);
00504 if (memguard)
00505 {
00506 memguard->release();
00507 }
00508 return;
00509 }
00510 if (aggressive)
00511 {
00512 MemoryTracer->checkMap();
00513 }
00514 owInternal = true;
00515 if (MemoryTracer != 0)
00516 {
00517 p = MemoryTracer->remove((void*)((char*)p));
00518 }
00519 else
00520 {
00521 printf("** MemTracer can't remove delete from map: ADDR: %x\n", (unsigned int)p);
00522 }
00523 if (!noFree)
00524 {
00525 free(p);
00526 }
00527 owInternal = false;
00528 memguard->release();
00529 }
00530 if (_shuttingDown)
00531 {
00532 memguard->release();
00533 fprintf(stderr, "delete called\n");
00534 }
00535 }
00536
00537 }
00538
00540 void*
00541 operator new[](std::size_t size, char const* file, int line) throw(std::bad_alloc)
00542 {
00543 return OW_NAMESPACE::doNew(size, file, line);
00544 }
00546 void*
00547 operator new(std::size_t size, char const* file, int line) throw(std::bad_alloc)
00548 {
00549 return OW_NAMESPACE::doNew(size, file, line);
00550 }
00552 void*
00553 operator new[](std::size_t size) throw(std::bad_alloc)
00554 {
00555 return OW_NAMESPACE::doNew(size, NULL, 0);
00556 }
00558 void*
00559 operator new(std::size_t size) throw(std::bad_alloc)
00560 {
00561 return OW_NAMESPACE::doNew(size, NULL, 0);
00562 }
00563 void
00564 operator delete(void* p)
00565 {
00566 OW_NAMESPACE::doDelete(p);
00567 }
00568 void
00569 operator delete[](void* p)
00570 {
00571 OW_NAMESPACE::doDelete(p);
00572 }
00573
00574
00575 #endif // OW_DEBUG_MEMORY
00576
00577