MPMA Framework 0.4
Memory.h
Go to the documentation of this file.
00001 
00002 
00015 
00016 //Luke Lenhart, 2001-2011
00017 //See /docs/License.txt for details on how this code may be used.
00018 
00019 #pragma once
00020 
00021 #include "Setup.h"
00022 
00023 //cut some harmless noise warnings out from msvc on warning level 4
00024 #if defined(_WIN32) || defined(_WIN64)
00025 #pragma warning(disable:4127) //conditional expression is constant.  example: do { ...etc... } while (false)
00026 #pragma warning(disable:4100) //unreferenced format parameter.  This seems to be a compiler bug... calling a destructor doesn't count as a "reference to" apparently.
00027 #endif
00028 
00029 
00030 // --
00031 
00032 #include <list>
00033 #include <string>
00034 #include <string.h> //for memset
00035 #include "Types.h"
00036 
00037 //internal use
00038 enum EMemAllocType
00039 {
00040     EMAT_None,
00041     EMAT_One,
00042     EMAT_Array
00043 };
00044 
00046 class MPMAMemoryManager
00047 {
00048 public:
00049     //returns whether the memory manager is ready to handle requests
00050     inline bool IsReady() const
00051         { return m_ready; }
00052 
00053     //Marks an allocation as "intentionally leaked".  It won't be reported on at framework shutdown.
00054     void MarkAsIntentionallyLeaked(void *mem);
00055 
00056     // -- internal use below
00057 
00058     //used by the allocation scheme, do not call directly - traces an alloc or free
00059     void TraceAlloc(EMemAllocType type, void *memory, void *object, nuint objectSize, nsint count, const char *file, int line, const char *name);
00060     EMemAllocType TraceFree(EMemAllocType type, volatile void *object, char *&outAllocMem, nsint *outObjectSize, nsint *outCount, const char *file, int line);
00061 
00062     //used by the allocation scheme, do not call directly
00063     void InternalInitialize();
00064     void InternalShutdown();
00065 
00066 #ifndef MEMMAN_TRACING // -- if NOT using management --
00067     //Returns if a specific pointer is an allocated object (always returns true if management is disabled)
00068     inline bool IsPointerAnObject(void *p)
00069         { return true; }
00070 
00071     //checks for memory corruption around all allocated memory
00072     inline void CheckForPaddingCorruption() {}
00073 #endif
00074 
00075 #ifdef MEMMAN_TRACING // -- if using management --
00076 
00077     //Returns if a specific pointer is an allocated object (always returns true if management is disabled)
00078     bool IsPointerAnObject(void *p);
00079 
00080     //checks for memory corruption around all allocated memory
00081     void CheckForPaddingCorruption();
00082 
00083     struct SAlloc
00084     {
00085         EMemAllocType type;
00086         void *objAddr; //object address
00087         void *allocMem; //container memory
00088         nuint size;
00089         std::string srcFile;
00090         int srcLine;
00091         nsint count; //number in array
00092         std::string allocStack;
00093         std::string deleteStack;
00094         std::string name;
00095         bool countsAsLeak; //true for anything allocated between init and shutdown
00096 
00097         SAlloc *next;
00098 
00099         std::string Describe();
00100     };
00101 
00102 private:
00103     bool m_critErrors; //did any critical memory errors occur?
00104 
00105     SAlloc *m_head; //first item in linked list of allocations
00106 
00107     //used internally
00108     bool VerifyAllocPadding(uint8 *mem, nuint objSize);
00109 
00110     //used as part of mapping the difference between the memory we provide for an object and the memory new return to the caller
00111     struct SMapAllocDifference
00112     {
00113         void *actual;
00114         void *returned;
00115     };
00116     std::list<SMapAllocDifference> allocDifferences;
00117 
00118 #endif // -- end if using management --
00119 
00120     //calls back to the leak report callbacks
00121     void ReportLeak(const std::string &leak);
00122 
00123     bool m_ready; //class ready to handle requests
00124 
00125 public: //internal use, do not call directly
00126 #ifdef MEMMAN_TRACING // -- if using management --
00127     //calls an objects destructor
00128     template <typename T> static void dbgN2_Destruct(T *obj)
00129     {
00130         obj->~T();
00131     }
00132     template <typename T> static void dbgN2_Destruct_array(T *obj, nsint count)
00133     {
00134         for (nsint i=0; i<count; ++i)
00135         {
00136             obj->~T();
00137             ++obj;
00138         }
00139     }
00140 
00141     //used as part of tracking a allocation differences
00142     template <typename T> static T dbgN3_ReturnNew(T obj)
00143     {
00144         AllocDifferenceMapEnd(obj);
00145         return obj;
00146     }
00147 
00148     static void AllocDifferenceMapStart(void *mem);
00149     static void AllocDifferenceMapEnd(void *mem);
00150 
00151     static void* DeallocDifferenceMap(void *mem, bool pop);
00152 #endif // -- end if using management --
00153 
00154     MPMAMemoryManager();
00155     ~MPMAMemoryManager();
00156 
00157 };
00158 
00159 extern MPMAMemoryManager mpmaMemoryManager;
00160 
00161 #ifndef MEMMAN_TRACING // -- if NOT using management --
00162 inline void MPMAMemoryManager::MarkAsIntentionallyLeaked(void *mem) {}
00163 #endif
00164 
00165 #ifdef MEMMAN_TRACING // -- if using management --
00166 
00167 //bytes on each side of an allocation that are used to check for damage
00168 #define dbgN2_padding 8
00169 
00170 //allocators that store tracing information
00171 void* operator new(size_t objLen, MPMAMemoryManager *theMan, const char *file, int line, const char *name);
00172 
00173 #define new3(obj)       MPMAMemoryManager::dbgN3_ReturnNew(new (&mpmaMemoryManager, __FILE__, __LINE__, ""#obj) obj)
00174 #define new2(obj, junk) new3(obj)
00175 
00176 void* operator new[](size_t objLen, MPMAMemoryManager *theMan, size_t count, const char *file, int line, const char *name);
00177 
00178 #define new3_array(obj, count)       MPMAMemoryManager::dbgN3_ReturnNew(new (&mpmaMemoryManager, count, __FILE__, __LINE__, ""#obj) obj[count])
00179 #define new2_array(obj, count, junk) new3_array(obj, count)
00180 
00181 //freers that match the above allocators
00182 
00183 void operator delete(void *obj, MPMAMemoryManager *theMan, const char *file, int line, const char *name);
00184 
00185 void operator delete[](void *obj, MPMAMemoryManager *theMan, size_t count, const char *file, int line, const char *name);
00186 
00187 #define delete3(obj) \
00188 do { \
00189     void *pObj=(void*)(obj); \
00190     nsint count=0; \
00191     nsint objSize=0; \
00192     char *realMem=0; \
00193     EMemAllocType type=mpmaMemoryManager.TraceFree(EMAT_One, pObj, realMem, &objSize, &count, __FILE__, __LINE__); \
00194     if (type==EMAT_One) MPMAMemoryManager::dbgN2_Destruct(obj); \
00195     else if (type==EMAT_Array) MPMAMemoryManager::dbgN2_Destruct_array(obj, count); \
00196     memset(pObj, 0x7e, objSize); \
00197     delete[] realMem; \
00198     *((nuint**)&obj)=(nuint*)-1; \
00199 } while(false)
00200 
00201 #define delete2(obj) delete3(obj) 
00202 
00203 #define delete3_array(obj) \
00204 do { \
00205     void *pObj=(void*)(obj); \
00206     nsint count=0; \
00207     nsint objSize=0; \
00208     char *realMem=0; \
00209     EMemAllocType type=mpmaMemoryManager.TraceFree(EMAT_Array, pObj, realMem, &objSize, &count, __FILE__, __LINE__); \
00210     if (type==EMAT_One) MPMAMemoryManager::dbgN2_Destruct(obj); \
00211     else if (type==EMAT_Array) MPMAMemoryManager::dbgN2_Destruct_array(obj, count); \
00212     memset(pObj, 0x7e, objSize); \
00213     delete[] realMem; \
00214     *((nuint**)&obj)=(nuint*)-1; \
00215 } while(false)
00216 
00217 #define delete2_array(obj) delete3_array(obj)
00218 
00219 #else // -- if NOT using management --
00220 
00221     #define new3(obj) new obj
00222     #define new2(obj,junk) new obj
00223     #define new3_array(obj,count) new obj[count]
00224     #define new2_array(obj,count,junk) new obj[count]
00225 
00226     #define delete3(obj) delete obj
00227     #define delete2(obj) delete obj
00228     #define delete3_array(obj) delete[] obj
00229     #define delete2_array(obj) delete[] obj
00230 
00231 #endif // -- end if using management --
00232 
00233 // -- custom deleter for shared_ptr and similar use
00234 template <typename T>
00235 class new3_delete
00236 {
00237 public:
00238     void operator()(T *p)
00239     {
00240         delete3(p);
00241     }
00242 };
00243 
00244 template <typename T>
00245 class new3_array_delete
00246 {
00247 public:
00248     void operator()(T *p)
00249     {
00250         delete3_array(p);
00251     }
00252 };
00253 
00254 // -- auto scope pointer freer --
00255 
00256 namespace MPMA
00257 {
00259     template <typename T>
00260     class AutoDelete
00261     {
00262     public:
00263         inline AutoDelete(T *inPtr): ptr(inPtr) {}
00264         inline ~AutoDelete() {if (ptr) delete2(ptr);}
00265     private:
00266         T *ptr;
00267     };
00268 
00270     template <typename T>
00271     class AutoDeleteArray
00272     {
00273     public:
00274         inline AutoDeleteArray(T *inPtr): ptr(inPtr) {}
00275         inline ~AutoDeleteArray() {if (ptr) delete2_array(ptr);}
00276     private:
00277         T *ptr;
00278     };
00279 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends