source: src/Helpers/MemDebug.cpp@ 93dfc7b

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 93dfc7b was 93dfc7b, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Made the delete handle deletion of NULL pointers more gracefully

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