OW_MemTracer.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NO T LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
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 // need to use our own allocator to avoid a deadlock with the standard allocator locking with a non-recursive mutex.
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             // don't let exceptions escape
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       // don't let exceptions escape
00250    }
00251 }
00252 //static int delCount = 0;
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 } // end namespace OW_NAMESPACE
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 

Generated on Thu Feb 9 08:48:05 2006 for openwbem by  doxygen 1.4.6