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