Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/MemoryTracer

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: MemoryTracer 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.5 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022   
00023 ****************************************************************************/
00024 
00025 #ifndef _BASE_MEMORYTRACER_
00026 #define _BASE_MEMORYTRACER_
00027 
00028 #include <base/base>
00029 #include <string>
00030 
00031 
00032 namespace base {
00033 
00034 
00035 
00036 #ifdef DEBUG
00037 
00038 // if this is defined, memory is traced, otherwise the global new/delete operators are
00039 //  not overloaded
00040 //#define _TRACEMEMORY_
00041 
00042 // if this is defined and tracing is being used, the new and delete operators will output to stderr
00043 //#define TRACEOUTPUT
00044 
00045 // if this is defined and TRACEOUTPUT is defined, then new/delete will only output named allocations
00046 #define _NAMEDOUTPUTONLY_
00047 
00048 
00049 // if this is defined, extra integrity checks will be performed for memory overwrite
00050 // (these are very slow).
00051 #define _FULLINTEGRITYCHECK_ 1
00052 
00053 // if 1, a full memory check is performed on every call to new or delete
00054 // if 0, a check is never performed (except by excplict call to checkAllMemory())
00055 // if n, a full memory check is performed on every n'th call to new or delete
00056 #define _FULLCHECKFREQUENTY_ 100
00057 
00058 
00059 #endif
00060 
00061 
00062 
00063 
00064   class MemoryTracer
00065   {
00066   public:
00067     static void* allocate(int size, const std::string& name, bool isArray=false) throw(std::bad_alloc);
00068     static bool release(void* address, bool isArray=false, int size = -1) throw(std::bad_alloc);
00069     static bool validate(void *address, int size, const std::string& name) throw(std::bad_alloc);
00070     static bool invalidate(void* address, int size) throw(std::bad_alloc);
00071 
00072     static void* checkAddrRange(void* address, long typesize) throw(std::bad_alloc);
00073     static bool checkAddr(void* address, void* reportAddr = 0, bool checkAllMemory = true) throw(std::bad_alloc);
00074     static bool checkAllMemory() throw(std::bad_alloc);
00075 
00076     static char* getName(void* addr);
00077     static long  getOffset(void* addr);
00078 
00079     static bool cleanup();
00080     static void menu() throw(std::bad_alloc);
00081     static void dump() ;
00082     static void dumpNamed();
00083     static void dumpDeallocated();
00084     static void handleError() throw(std::bad_alloc);
00085 
00086   protected:
00087     static void Logerr(char* errstr);
00088     static void entrylock();
00089     static void exitunlock();
00090     static int causefault();
00091     static void fill() 
00092     {
00093       for(Int i=0; i<Filling; i++) 
00094         prefill[i]  = postfill[i] = Filler;
00095     }
00096 
00097     static bool isOK() 
00098     {
00099       if (initialized != (Byte)Magic) { 
00100         initialized = (Byte)Magic;
00101         fill();
00102         return true;
00103       }
00104 #ifdef _FULLINTEGRITYCHECK_
00105       for(Int i=0; i<Filling; i++) 
00106         if ((prefill[i] != Filler) || (postfill[i] != Filler)) return false;
00107 #endif
00108       return true;
00109     }
00110     
00111     static const Byte Filling = 8;    // no of extra bytes to add before & after allocated memory 
00112     static const Byte Filler = 0xea;  // byte placed in filling space for integrity check 
00113     static const int Magic = 13456;   // must be < 16384 
00114     static const int External = 32768;// mask for marking mem as external 
00115     
00116     static const int IsArray;
00117     static const int IsNotArray;
00118     
00119     struct AllocEntry {
00120       bool isExternal() const { return (magic & External); }
00121       void setExternal() { magic = (External | Magic); }
00122       void clearExternal() { magic = Magic; }
00123       void setMagic() { magic = Magic; }
00124       bool isMagic() const { return ((magic&Magic) == Magic); }
00125       bool isNotMagic() const { return !isMagic(); }
00126       
00127       void fill() 
00128       {
00129         for(Int i=0; i<Filling; i++) 
00130           prefill[i]  = postfill[i] = Filler;
00131       }
00132 
00133       bool isOK() const 
00134       {
00135 #ifdef _FULLINTEGRITYCHECK_
00136         for(Int i=0; i<Filling; i++) 
00137           if ((prefill[i] != Filler) || (postfill[i] != Filler)) return false;
00138       if ((arrayFlag != MemoryTracer::IsArray) && (arrayFlag != MemoryTracer::IsNotArray)) return false;
00139 #endif
00140         if (size<=0) return false;
00141         if (isNotMagic()) return false;
00142         return true;
00143       }
00144 
00145       bool isArray() { return arrayFlag == MemoryTracer::IsArray; }
00146       void setIsArray(bool isAnArray) { arrayFlag = isAnArray?MemoryTracer::IsArray:MemoryTracer::IsNotArray; }
00147       
00148       Byte prefill[Filling]; // Filler for check integrity of list
00149       int size;
00150       Byte* address;
00151       int arrayFlag;
00152       char* name;
00153       int magic;
00154 
00155       AllocEntry* prev;
00156       AllocEntry* next;
00157 
00158       Byte postfill[Filling]; // Filler for check integrity of list
00159     };
00160 
00161     
00162     class AllocList
00163     {
00164     public:
00165       void push_front(AllocEntry* e);
00166       void push_back(AllocEntry* e);
00167       AllocEntry* pop_back();
00168       AllocEntry* pop_front();
00169       void remove(AllocEntry* e);
00170 
00171       AllocEntry* front() const { return head; }
00172       AllocEntry* back() const { return tail; }
00173       int size() const { return len; }
00174 
00175       AllocEntry* find(void* address, AllocEntry* from = 0) const;
00176 
00177     protected:
00178       // NB: Because new/delete may be called before the global construction of 
00179       //  static AllocList members of MemoryTracer, we rely on the following
00180       //  fields to have been initialized to 0 by the compiler!
00181       AllocEntry* head; // front
00182       AllocEntry* tail; // back
00183       Int len;
00184     };
00185 
00186     static const int DList_Max = 1000;
00187 
00188     static Byte prefill[Filling]; // Filler for integrity check
00189 
00190     static Byte initialized;
00191     static bool cleanedUp;
00192     static Int entry;
00193     static Int fullCheckCounter;
00194     static LInt allocCount;
00195     static LInt deallocCount;
00196     static LInt checkCount;
00197 
00198     static AllocList mlist; // the allocated memory list
00199     static AllocList dlist; // list of memory allocated and then deallocated (so we can catch double delete's)
00200 
00201     static Byte postfill[Filling]; // Filler for integrity check
00202   };
00203 
00204 
00205   void stressTestAllocator();
00206 
00207 
00208 } // base
00209 
00210 
00211 
00212 #ifdef _TRACEMEMORY_
00213 void* operator new(size_t size) throw (std::bad_alloc);
00214 void* operator new[](size_t size) throw (std::bad_alloc);
00215 void* operator new(size_t size, const std::string& name) throw (std::bad_alloc);
00216 void* operator new[](size_t size, const std::string& name) throw (std::bad_alloc);
00217 void operator delete(void* p) throw();
00218 void operator delete[](void* p) throw();
00219 
00220 //#define NewObj new(std::string(__FILE__)+":"+base::intToString(__LINE__))
00221 //#define NewNamedObj(name) new(std::string(__FILE__)+":"+base::intToString(__LINE__)+":"+name)
00222 #define NewObj new
00223 #define NewNamedObj(name) new
00224 #define DeleteObj delete
00225 
00226 #else
00227 
00228 inline void* operator new(size_t size, const std::string& name) throw (std::bad_alloc)
00229 { return ::operator new(size); }
00230 inline void* operator new[](size_t size, const std::string& name) throw (std::bad_alloc)
00231 { return ::operator new[](size); }
00232 
00233 #define NewObj new
00234 #define NewNamedObj(name) new
00235 #define DeleteObj delete
00236 
00237 #endif
00238 
00239 
00240 
00241 #endif
00242 

Generated on Thu Jul 29 15:56:08 2004 for OpenSim by doxygen 1.3.6