Changes in src/Helpers/MemDebug.cpp [68f03d:28c351]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Helpers/MemDebug.cpp
r68f03d r28c351 13 13 14 14 namespace Memory { 15 16 // This struct is added before each memory chunk17 // and contains tracking information. Anything used18 // to track memory cannot use any dynamic memory, so19 // we have to resort to classic C-idioms here.20 // This struct also contains pointers to the next21 // an previous chunks to allow fast traversion of22 // all allocated memory blocks23 15 struct entry_t { 24 // we seperate the tracking info from the rest25 // A checksum will be calculated for this part of26 // the struct, so the information in here should27 // not change during the lifetime of the memory28 16 struct info_t { 29 enum {length = 64}; 30 char file[length+1]; 17 char file[256]; 31 18 int line; 32 19 size_t nbytes; … … 40 27 }; 41 28 42 // start and end of the doubly-linked list43 29 entry_t *begin=0; 44 30 entry_t *end=0; 45 31 46 // current amount of allocated memory47 32 size_t state = 0; 48 // maximum amount of allocated memory49 33 size_t max = 0; 50 // number of allocations that have been done so far51 unsigned int allocs = 0;52 34 53 54 // this sets the alignment of the returned memory block55 // malloc guarantees an alignment at the 8 byte border,56 // so we just do the same57 35 const int alignment = 8; 58 36 59 // calculates a simple checksum for the info block60 // the checksum is used to find memory corruptions61 37 inline char calcChecksum(entry_t::info_t *info){ 62 38 char *buffer = (char*)info; … … 68 44 } 69 45 70 // gets the next alignet point which is greater than nbytes71 // this function is only called a fixed number of times, so72 // there is no need to optimize73 46 inline size_t doAlign(size_t nbytes){ 74 47 int nonaligned = nbytes % alignment; … … 81 54 } 82 55 83 // Output some state information84 56 void getState(){ 85 57 cout << "Maximum allocated Memory: " << max << " bytes" << endl; 86 58 cout << "Currently allocated Memory: " << state <<" bytes" << endl; 87 cout << allocs << " allocated chunks total" << endl;88 59 89 // simple traversal of the chunk list90 60 for(entry_t *pos=begin;pos;pos=pos->next){ 91 61 cout << "\nChunk of " << pos->info.nbytes << " bytes" << " still available" << endl; … … 94 64 } 95 65 96 // Deletes an entry from the linked list97 66 void deleteEntry(entry_t *entry){ 98 67 if(entry->isIgnored) 99 68 return; 100 101 69 if(entry->prev){ 102 70 entry->prev->next = entry->next; 103 71 } 104 72 else{ 105 // this node was the beginning of the list106 73 begin = entry->next; 107 74 } … … 111 78 } 112 79 else{ 113 // this node was the end of the list114 80 end = entry->prev; 115 81 } … … 119 85 120 86 void _ignore(void *ptr){ 121 // just deletes the node from the list, but leaves the info intact122 87 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t)); 123 88 entry_t *entry = (Memory::entry_t*)((char*)ptr-entrySpace); … … 128 93 void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) { 129 94 130 // to avoid allocations of 0 bytes if someone screws up131 // allocation with 0 byte size are undefined behavior, so we are132 // free to handle it this way133 95 if(!nbytes) { 134 96 nbytes = 1; 135 97 } 136 98 137 // get the size of the entry, including alignment138 99 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t)); 139 100 140 101 void *res; 141 102 if(!(res=malloc(entrySpace + nbytes))){ 142 // new must throw, when space is low143 103 throw std::bad_alloc(); 144 104 } 145 105 146 // we got the space, so update the global info147 106 Memory::state += nbytes; 148 107 if(Memory::state>Memory::max){ 149 108 Memory::max = Memory::state; 150 109 } 151 Memory::allocs++;152 110 153 // build the entry in front of the space154 111 Memory::entry_t *entry = (Memory::entry_t*) res; 155 memset(res,0,entrySpace);156 112 entry->info.nbytes = nbytes; 157 113 entry->info.isUsed = true; 158 strncpy(entry->info.file,file, Memory::entry_t::info_t::length);159 entry->info.file[ Memory::entry_t::info_t::length] = '\0';114 strncpy(entry->info.file,file,256); 115 entry->info.file[255] = '\0'; 160 116 entry->info.line=line; 161 // the space starts behind the info162 117 entry->info.location = (char*)res + entrySpace; 163 118 164 // add the entry at the end of the list 165 entry->next=0; // the created block is last in the list 166 entry->prev=Memory::end; // the created block is last in the list 119 entry->next=0; 120 entry->prev=Memory::end; 167 121 if(!Memory::begin){ 168 // the list was empty... start a new one169 122 Memory::begin=entry; 170 123 } 171 124 else { 172 // other blocks present... we can add to the last one173 125 Memory::end->next=entry; 174 126 } 175 127 Memory::end=entry; 176 128 177 // get the checksum...178 129 entry->checksum = Memory::calcChecksum(&entry->info); 179 // this will be set to true, when the block is removed from180 // the list for any reason181 130 entry->isIgnored = false; 182 131 183 // ok, space is prepared... the user can have it.184 // the rest (constructor, deleting when something is thrown etc)185 // is handled automatically186 132 return entry->info.location; 187 133 } 188 134 189 135 void *operator new(size_t nbytes) throw(std::bad_alloc) { 190 // Just forward to the other operator, when we do not know from191 // where the allocation came192 136 return operator new(nbytes,"Unknown",0); 193 137 } 194 138 195 139 void *operator new[] (size_t nbytes,const char* file, int line) throw(std::bad_alloc) { 196 // The difference between new and new[] is just for compiler bookkeeping.197 140 return operator new(nbytes,file,line); 198 141 } 199 142 200 143 void *operator new[] (size_t nbytes) throw(std::bad_alloc) { 201 // Forward again202 144 return operator new[] (nbytes,"Unknown",0); 203 145 } 204 146 205 147 void operator delete(void *ptr) throw() { 206 // get the size for the entry, including alignment207 148 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t)); 208 149 209 // get the position for the entry from the pointer the user gave us210 150 Memory::entry_t *entry = (Memory::entry_t*)((char*)ptr-entrySpace); 211 151 212 // let's see if the checksum is still matching213 152 if(Memory::calcChecksum(&entry->info)!=entry->checksum){ 214 153 cout << "Possible memory corruption detected!" << endl; … … 218 157 } 219 158 220 // this will destroy the checksum, so double deletes are caught221 159 entry->info.isUsed = false; 222 160 Memory::deleteEntry(entry); 223 161 224 // delete the space reserved by malloc225 162 free((char*)ptr-entrySpace); 226 163 } 227 164 228 // operator that is called when the constructor throws229 // do not call manually230 165 void operator delete(void *ptr,const char*, int) throw() { 231 166 operator delete(ptr); … … 233 168 234 169 void operator delete[](void *ptr){ 235 // again difference between delete and delete[] is just in compiler bookkeeping236 170 operator delete(ptr); 237 171 } 238 172 239 // and another operator that can be called when a constructor throws240 173 void operator delete[](void *ptr,const char*, int) throw(){ 241 174 operator delete(ptr);
Note:
See TracChangeset
for help on using the changeset viewer.