source: molecuilder/src/Helpers/MemDebug.cpp@ 4eee8f

Last change on this file since 4eee8f was c53e0b, checked in by Frederik Heber <heber@…>, 16 years ago

Merge branch 'FixMemDebug_strncpy' into StructureRefactoring

  • Property mode set to 100644
File size: 7.0 KB
RevLine 
[90c4460]1/*
2 * MemDebug.cpp
3 *
4 * Created on: Apr 28, 2010
5 * Author: crueger
6 */
7
8#include <iostream>
9#include <cstdlib>
[93b12d]10#include <cstring>
[90c4460]11
12using namespace std;
13
14namespace Memory {
[5d1a94]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
[90c4460]23 struct entry_t {
[5d1a94]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
[90c4460]28 struct info_t {
[5d1a94]29 enum {length = 64};
[16eb32]30 char file[length+1];
[90c4460]31 int line;
32 size_t nbytes;
33 bool isUsed;
34 void *location;
35 } info;
36 bool isIgnored;
37 char checksum;
38 entry_t *prev;
39 entry_t *next;
40 };
41
[5d1a94]42 // start and end of the doubly-linked list
[90c4460]43 entry_t *begin=0;
44 entry_t *end=0;
45
[5d1a94]46 // current amount of allocated memory
[90c4460]47 size_t state = 0;
[5d1a94]48 // maximum amount of allocated memory
[90c4460]49 size_t max = 0;
[5d1a94]50 // number of allocations that have been done so far
51 unsigned int allocs = 0;
52
[90c4460]53
[5d1a94]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
[90c4460]57 const int alignment = 8;
58
[5d1a94]59 // calculates a simple checksum for the info block
60 // the checksum is used to find memory corruptions
[90c4460]61 inline char calcChecksum(entry_t::info_t *info){
62 char *buffer = (char*)info;
63 char checksum =0;
64 for(size_t i=0;i<sizeof(entry_t::info_t);i++){
65 checksum+=buffer[i];
66 }
67 return checksum;
68 }
69
[5d1a94]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
[90c4460]73 inline size_t doAlign(size_t nbytes){
74 int nonaligned = nbytes % alignment;
75 if(nonaligned) {
76 return(nbytes - nonaligned + alignment);
77 }
78 else{
79 return nbytes;
80 }
81 }
82
[5d1a94]83 // Output some state information
[90c4460]84 void getState(){
85 cout << "Maximum allocated Memory: " << max << " bytes" << endl;
86 cout << "Currently allocated Memory: " << state <<" bytes" << endl;
[5d1a94]87 cout << allocs << " allocated chunks total" << endl;
[90c4460]88
[5d1a94]89 // simple traversal of the chunk list
[90c4460]90 for(entry_t *pos=begin;pos;pos=pos->next){
91 cout << "\nChunk of " << pos->info.nbytes << " bytes" << " still available" << endl;
92 cout << "Chunk reserved at: " << pos->info.file << ":" << pos->info.line << endl;
93 }
94 }
95
[5d1a94]96 // Deletes an entry from the linked list
[90c4460]97 void deleteEntry(entry_t *entry){
98 if(entry->isIgnored)
99 return;
[5d1a94]100
[90c4460]101 if(entry->prev){
102 entry->prev->next = entry->next;
103 }
104 else{
[5d1a94]105 // this node was the beginning of the list
[90c4460]106 begin = entry->next;
107 }
108
109 if(entry->next){
110 entry->next->prev = entry->prev;
111 }
112 else{
[5d1a94]113 // this node was the end of the list
[90c4460]114 end = entry->prev;
115 }
116 entry->isIgnored = true;
117 Memory::state -= entry->info.nbytes;
118 }
119
120 void _ignore(void *ptr){
[5d1a94]121 // just deletes the node from the list, but leaves the info intact
[90c4460]122 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t));
123 entry_t *entry = (Memory::entry_t*)((char*)ptr-entrySpace);
124 deleteEntry(entry);
125 }
126}
127
128void *operator new(size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
129
[5d1a94]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
[90c4460]133 if(!nbytes) {
134 nbytes = 1;
135 }
136
[5d1a94]137 // get the size of the entry, including alignment
[90c4460]138 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t));
139
140 void *res;
141 if(!(res=malloc(entrySpace + nbytes))){
[5d1a94]142 // new must throw, when space is low
[90c4460]143 throw std::bad_alloc();
144 }
145
[5d1a94]146 // we got the space, so update the global info
[90c4460]147 Memory::state += nbytes;
148 if(Memory::state>Memory::max){
149 Memory::max = Memory::state;
150 }
[5d1a94]151 Memory::allocs++;
[90c4460]152
[5d1a94]153 // build the entry in front of the space
[90c4460]154 Memory::entry_t *entry = (Memory::entry_t*) res;
155 entry->info.nbytes = nbytes;
156 entry->info.isUsed = true;
[5d1a94]157 strncpy(entry->info.file,file,Memory::entry_t::info_t::length);
[16eb32]158 entry->info.file[Memory::entry_t::info_t::length] = '\0';
[90c4460]159 entry->info.line=line;
[5d1a94]160 // the space starts behind the info
[90c4460]161 entry->info.location = (char*)res + entrySpace;
162
[5d1a94]163 // add the entry at the end of the list
164 entry->next=0; // the created block is last in the list
165 entry->prev=Memory::end; // the created block is last in the list
[90c4460]166 if(!Memory::begin){
[5d1a94]167 // the list was empty... start a new one
[90c4460]168 Memory::begin=entry;
169 }
170 else {
[5d1a94]171 // other blocks present... we can add to the last one
[90c4460]172 Memory::end->next=entry;
173 }
174 Memory::end=entry;
175
[5d1a94]176 // get the checksum...
[90c4460]177 entry->checksum = Memory::calcChecksum(&entry->info);
[5d1a94]178 // this will be set to true, when the block is removed from
179 // the list for any reason
[90c4460]180 entry->isIgnored = false;
181
[5d1a94]182 // ok, space is prepared... the user can have it.
183 // the rest (constructor, deleting when something is thrown etc)
184 // is handled automatically
[90c4460]185 return entry->info.location;
186}
187
188void *operator new(size_t nbytes) throw(std::bad_alloc) {
[5d1a94]189 // Just forward to the other operator, when we do not know from
190 // where the allocation came
[90c4460]191 return operator new(nbytes,"Unknown",0);
192}
193
194void *operator new[] (size_t nbytes,const char* file, int line) throw(std::bad_alloc) {
[5d1a94]195 // The difference between new and new[] is just for compiler bookkeeping.
[90c4460]196 return operator new(nbytes,file,line);
197}
198
199void *operator new[] (size_t nbytes) throw(std::bad_alloc) {
[5d1a94]200 // Forward again
[90c4460]201 return operator new[] (nbytes,"Unknown",0);
202}
203
204void operator delete(void *ptr) throw() {
[5d1a94]205 // get the size for the entry, including alignment
[90c4460]206 static const size_t entrySpace = Memory::doAlign(sizeof(Memory::entry_t));
207
[5d1a94]208 // get the position for the entry from the pointer the user gave us
[90c4460]209 Memory::entry_t *entry = (Memory::entry_t*)((char*)ptr-entrySpace);
210
[5d1a94]211 // let's see if the checksum is still matching
[90c4460]212 if(Memory::calcChecksum(&entry->info)!=entry->checksum){
213 cout << "Possible memory corruption detected!" << endl;
214 cout << "Trying to recover allocation information..." << endl;
215 cout << "Memory was allocated at " << entry->info.file << ":" << entry->info.line << endl;
216 terminate();
217 }
218
[5d1a94]219 // this will destroy the checksum, so double deletes are caught
[90c4460]220 entry->info.isUsed = false;
221 Memory::deleteEntry(entry);
222
[5d1a94]223 // delete the space reserved by malloc
[90c4460]224 free((char*)ptr-entrySpace);
225}
226
[5d1a94]227// operator that is called when the constructor throws
228// do not call manually
[90c4460]229void operator delete(void *ptr,const char*, int) throw() {
230 operator delete(ptr);
231}
232
233void operator delete[](void *ptr){
[5d1a94]234 // again difference between delete and delete[] is just in compiler bookkeeping
[90c4460]235 operator delete(ptr);
236}
237
[5d1a94]238// and another operator that can be called when a constructor throws
[90c4460]239void operator delete[](void *ptr,const char*, int) throw(){
240 operator delete(ptr);
241}
Note: See TracBrowser for help on using the repository browser.