Changes in src/Helpers/MemDebug.cpp [fc6053:f2f4ae]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified src/Helpers/MemDebug.cpp ¶
rfc6053 rf2f4ae 6 6 */ 7 7 8 #ifndef NDBEGUG9 #ifndef NO_MEMDEBUG10 11 8 #include <iostream> 12 9 #include <cstdlib> … … 14 11 #include <boost/thread.hpp> 15 12 16 #ifdef __GNUC__17 #include <execinfo.h>18 #include <cxxabi.h>19 #endif20 21 13 using namespace std; 22 14 23 // we need our own low level mutexex, since we cannot assure the time of construction and destruction 24 // otherwise 25 #if defined(unix) || defined(__unix) 26 27 #include <pthread.h> 28 #include <cassert> 29 #define mutex_t pthread_mutex_t 30 #define mutex_init PTHREAD_MUTEX_INITIALIZER 31 #define mutex_lock(mtx) \ 32 do{\ 33 int res = pthread_mutex_lock(&(mtx));\ 34 assert(!res && "Could not lock mutex!");\ 35 }while(0) 36 37 #define mutex_unlock(mtx) \ 38 do{\ 39 int res = pthread_mutex_unlock(&(mtx));\ 40 assert(!res && "Could not unlock mutex!");\ 41 }while(0) 42 43 #else 44 # error "No thread structure defined for this plattform..." 45 #endif 15 #ifndef NDBEGUG 16 #ifndef NO_MEMDEBUG 46 17 47 18 namespace Memory { … … 63 34 char file[length+1]; 64 35 int line; 65 #ifdef __GNUC__ // function tracking only works with GCC66 // function names can get looooong67 enum {length2 = 256};68 char function[length2+1];69 #endif70 36 size_t nbytes; 71 37 bool isUsed; … … 78 44 }; 79 45 80 81 mutex_t memorylock = mutex_init; 46 boost::mutex memorylock; 82 47 83 48 // start and end of the doubly-linked list … … 131 96 for(entry_t *pos=begin;pos;pos=pos->next){ 132 97 cout << "\nChunk of " << pos->info.nbytes << " bytes" << " still available" << endl; 133 #ifdef __GNUC__134 cout << "Chunk reserved at: " << pos->info.function135 << " (" << pos->info.file << ":" << pos->info.line << ")" << endl;136 #else137 98 cout << "Chunk reserved at: " << pos->info.file << ":" << pos->info.line << endl; 138 #endif 139 } 140 } 141 142 // Adds an entry to the linked list 143 void addEntry(entry_t *entry){ 144 // check if the entry is already in the list 145 if(!entry->isIgnored) 146 return; 147 148 mutex_lock(Memory::memorylock); 149 150 entry->next=0; // the created block is last in the list 151 entry->prev=Memory::end; // the created block is last in the list 152 if(!Memory::begin){ 153 // the list was empty... start a new one 154 Memory::begin=entry; 155 } 156 else { 157 // other blocks present... we can add to the last one 158 Memory::end->next=entry; 159 } 160 Memory::end=entry; 161 162 // update some global info 163 Memory::state += entry->info.nbytes; 164 if(Memory::state>Memory::max){ 165 Memory::max = Memory::state; 166 } 167 ++Memory::allocs; 168 // done with the list... it is safe to unlock now 169 mutex_unlock(Memory::memorylock); 170 entry->isIgnored = false; 99 } 171 100 } 172 101 … … 176 105 return; 177 106 178 mutex_lock(memorylock);179 107 if(entry->prev){ 180 108 entry->prev->next = entry->next; … … 192 120 end = entry->prev; 193 121 } 122 entry->isIgnored = true; 194 123 Memory::state -= entry->info.nbytes; 195 mutex_unlock(memorylock);196 entry->isIgnored = true;197 198 124 } 199 125 … … 204 130 deleteEntry(entry); 205 131 } 206 207 #ifdef __GNUC__ 208 // this function let's us find the caller's name 209 char* getCaller(){ 210 // stack looks like this: 211 // getCaller(); 212 // operator new(); 213 // function_we_are_looking_for(); <- 214 const size_t max_depth = 3; 215 void* stack_addrs[max_depth]; 216 size_t stack_depth; 217 char **stack_strings=0; 218 const char *func_name=0; 219 const char *toplevel = "Global scope"; 220 char *retval=0; 221 222 // get the backtrace, depth three 223 stack_depth = backtrace(stack_addrs,max_depth); 224 stack_strings = backtrace_symbols(stack_addrs, stack_depth); 225 // used later for demangling 226 // reserved here, so we can free it unconditionally 227 char *dm_function = static_cast<char*>(malloc(entry_t::info_t::length2)); 228 if(!dm_function){ 229 // malloc failed... we are out of luck 230 throw std::bad_alloc(); 231 } 232 233 // see if we found our function name 234 if(stack_depth==max_depth){ 235 // find the mangled function name 236 char *begin = stack_strings[max_depth-1]; 237 // function name starts with a ( 238 while(*begin && *begin!='(') ++begin; 239 char *end=begin; 240 while(*end && *end!='+') ++end; 241 242 // see if we found our function name 243 if(*begin && *end){ 244 *begin++ = 0; 245 *end = 0; 246 // use the C++ demangler 247 248 size_t sz = entry_t::info_t::length2; 249 int status; 250 char *func_ret = abi::__cxa_demangle(begin, dm_function, &sz, &status); 251 if(func_ret){ 252 // abi might have realloced... 253 dm_function = func_ret; 254 func_name = dm_function; 255 } 256 else{ 257 // demangling failed... get the function name without demangling 258 func_name = begin; 259 } 260 } 261 else{ 262 // function name not found... get the whole line 263 func_name = stack_strings[max_depth-1]; 264 } 265 266 } 267 else{ 268 func_name = toplevel; 269 } 270 271 // now we copy the desired function name 272 if((retval = static_cast<char*>(malloc(strlen(func_name)+1)))){ 273 // we know that the string will fit, so strcpy is safe here 274 strcpy(retval,func_name); 275 } 276 else{ 277 free(stack_strings); // malloc()ed by backtrace_symbols 278 free(dm_function); 279 // uh-uh ... seems we are out of luck for allocations now 280 throw std::bad_alloc(); 281 } 282 free(dm_function); 283 free(stack_strings); // malloc()ed by backtrace_symbols 284 return retval; 285 } 286 #endif 287 } 288 289 #ifdef __GNUC__ 290 291 void *operator new(size_t nbytes,const char* file, int line, const char* func) throw(std::bad_alloc) { 132 } 133 134 void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) { 135 136 // we need to lock, so that no one changes the linked list while we are here 137 boost::mutex::scoped_lock guard(Memory::memorylock); 292 138 293 139 // to avoid allocations of 0 bytes if someone screws up … … 307 153 } 308 154 309 // build the entry in front of the space 310 Memory::entry_t *entry = (Memory::entry_t*) res; 311 memset(res,0,entrySpace); 312 entry->info.nbytes = nbytes; 313 entry->info.isUsed = true; 314 strncpy(entry->info.file,file,Memory::entry_t::info_t::length); 315 entry->info.file[Memory::entry_t::info_t::length] = '\0'; 316 entry->info.line=line; 317 strncpy(entry->info.function,func,Memory::entry_t::info_t::length2); 318 entry->info.function[Memory::entry_t::info_t::length2] = '\0'; 319 // the space starts behind the info 320 entry->info.location = (char*)res + entrySpace; 321 322 // mark the block as not in the list (will be changed by addEntry) 323 entry->isIgnored = true; 324 Memory::addEntry(entry); 325 326 // get the checksum... 327 entry->checksum = Memory::calcChecksum(&entry->info); 328 329 // ok, space is prepared... the user can have it. 330 // the rest (constructor, deleting when something is thrown etc) 331 // is handled automatically 332 return entry->info.location; 333 } 334 335 #else 336 337 void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) { 338 339 // to avoid allocations of 0 bytes if someone screws up 340 // allocation with 0 byte size are undefined behavior, so we are 341 // free to handle it this way 342 if(!nbytes) { 343 nbytes = 1; 344 } 345 346 // get the size of the entry, including alignment 347 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t)); 348 349 void *res; 350 if(!(res=malloc(entrySpace + nbytes))){ 351 // new must throw, when space is low 352 throw std::bad_alloc(); 353 } 155 // we got the space, so update the global info 156 Memory::state += nbytes; 157 if(Memory::state>Memory::max){ 158 Memory::max = Memory::state; 159 } 160 Memory::allocs++; 354 161 355 162 // build the entry in front of the space … … 364 171 entry->info.location = (char*)res + entrySpace; 365 172 366 // mark the block as not in the list (will be changed by addEntry) 367 entry->isIgnored = true; 368 Memory::addEntry(entry); 173 // add the entry at the end of the list 174 entry->next=0; // the created block is last in the list 175 entry->prev=Memory::end; // the created block is last in the list 176 if(!Memory::begin){ 177 // the list was empty... start a new one 178 Memory::begin=entry; 179 } 180 else { 181 // other blocks present... we can add to the last one 182 Memory::end->next=entry; 183 } 184 Memory::end=entry; 369 185 370 186 // get the checksum... … … 380 196 } 381 197 382 #endif383 384 198 void *operator new(size_t nbytes) throw(std::bad_alloc) { 385 199 // Just forward to the other operator, when we do not know from 386 200 // where the allocation came 387 #ifdef __GNUC__388 // this might throw bad_alloc389 char *caller = Memory::getCaller();390 void* retval = 0;391 392 // if this throws, we have to clean up the caller anyway393 try{394 retval = operator new(nbytes,"Unknown",0,caller);395 }396 catch(...)397 {398 free(caller); // malloc()ed by Memory::getCaller();399 throw;400 }401 free(caller); // malloc()ed by Memory::getCaller();402 return retval;403 #else404 201 return operator new(nbytes,"Unknown",0); 405 #endif 406 } 407 408 #ifdef __GNUC__ 409 410 void *operator new[] (size_t nbytes,const char* file, int line, const char* func) throw(std::bad_alloc) { 411 // The difference between new and new[] is just for compiler bookkeeping. 412 return operator new(nbytes,file,line,func); 413 } 414 415 #else 202 } 416 203 417 204 void *operator new[] (size_t nbytes,const char* file, int line) throw(std::bad_alloc) { … … 420 207 } 421 208 422 #endif423 424 209 void *operator new[] (size_t nbytes) throw(std::bad_alloc) { 425 210 // Forward again 426 #ifdef __GNUC__427 // this might throw bad_alloc428 char *caller = Memory::getCaller();429 void *retval=0;430 431 // if this throws, we have to clean up the caller anyway432 try{433 retval = operator new[] (nbytes,"Unknown",0,caller);434 }435 catch(...)436 {437 free(caller); // malloc()ed by Memory::getCaller();438 throw;439 }440 free(caller); // malloc()ed by Memory::getCaller();441 return retval;442 #else443 211 return operator new[] (nbytes,"Unknown",0); 444 #endif445 212 } 446 213 … … 450 217 return; 451 218 } 219 220 // we need to lock, so the linked list does not changed while we are in here 221 boost::mutex::scoped_lock guard(Memory::memorylock); 452 222 453 223 // get the size for the entry, including alignment
Note:
See TracChangeset
for help on using the changeset viewer.