MPMA Framework 0.4
|
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 }