1 /*
2  * Modification History
3  *
4  * 2002-October-17   Jason Rohrer
5  * Created.
6  *
7  * 2002-October-18  Jason Rohrer
8  * Changed to use custom list instead of SimpleVector because SimpleVector
9  * uses debugMemory.
10  * Added static initialization counting class.
11  * Changed to use struct and malloc for AllocationList to avoid
12  * circular new and delete calls.
13  *
14  * 2002-October-19  Jason Rohrer
15  * Changed to print leak list upon final destruction.
16  * Improved printing behavior.
17  * Added support for clearing memory on allocation and deallocation.
18  *
19  * 2002-October-20  Jason Rohrer
20  * Removed file and line arguments from deallocation calls.
21  */
22 
23 
24 
25 #ifndef MEMORY_TRACK_INCLUDED
26 #define MEMORY_TRACK_INCLUDED
27 
28 
29 
30 #include "minorGems/system/MutexLock.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 
34 
35 #define SINGLE_ALLOCATION  0
36 #define ARRAY_ALLOCATION   1
37 
38 
39 
40 /**
41  * Linked list of memory allocations.
42  *
43  * @author Jason Rohrer
44  */
45 typedef struct {
46 
47         void *mPrevious;
48         void *mNext;
49 
50         void *mPointer;
51         unsigned int mAllocationSize;
52         int mAllocationType;
53         const char *mFileName;
54         int mLineNumber;
55 
56     } AllocationList;
57 
58 
59 
60 /**
61  * Class that tracks memory allocations and deallocations.
62  *
63  * @author Jason Rohrer
64  */
65 class MemoryTrack {
66 
67 
68 
69     public:
70 
71 
72 
73         /**
74          * Adds an allocation to this tracker and clears the allocated
75          * memory block.
76          *
77          * @param inPointer a pointer to the allocated memory.
78          * @param inAllocationType the type of allocation,
79          *   either SINGLE_ALLOCATION or ARRAY_ALLOCATION.
80          * @param inAllocationSize the size of the allocation in bytes.
81          * @param inFileName the name of the source file in which the
82          *   allocation took place.
83          * @param inLineNumber the line number in the source file
84          *   on which the allocation took place.
85          */
86         static void addAllocation( void *inPointer,
87                                    unsigned int inAllocationSize,
88                                    int inAllocationType,
89                                    const char *inFileName,
90                                    int inLineNumber );
91 
92 
93 
94         /**
95          * Adds a deallocation to this tracker and clears the block
96          * to be deallocated.
97          * Must be called *before* the memory is deallocated
98          *
99          * @param inPointer a pointer to the memory being deallocated.
100          * @param inDeallocationType the type of deallocation,
101          *   either SINGLE_ALLOCATION or ARRAY_ALLOCATION.
102          * @return 0 if the deallocation deallocates
103          *   an allocated block of memory, or 1 if it
104          *   deallocates a block of memory that is not currently allocated,
105          *   and 2 if it is the wrong deallocation type for the specified
106          *   block.
107          */
108         static int addDeallocation( void *inPointer, int inDeallocationType );
109 
110 
111 
112 
113         /**
114          * Prints a list of all memory leaks (allocations that have never
115          * been deallocated).
116          */
117         static void printLeaks();
118 
119 
120 
121         // these are public so initializer can get to them
122 
123         static MutexLock *mLock;
124 
125         // dummy place holder for list head
126         static AllocationList *mListHead;
127 
128         // true if we're tracking
129         static char mTracking;
130 
131         static int mTotalAllocationSize;
132 
133         static int mTotalDeallocationSize;
134 
135         static int mNumberOfAllocations;
136 
137     protected:
138 
139 
140 
141         /**
142          * Clears memory so that reading from it will not produce
143          * anything useful.  Good for checking for reads to memory that
144          * has been deallocated.
145          *
146          * @param inPointer pointer to the memory to clear.
147          * @Param inSize the number of bytes to clear starting at inPointer.
148          */
149         static void clearMemory( void *inPointer, unsigned int inSize );
150 
151 
152 
153     };
154 
155 
156 
157 /**
158  * Class that initializes MemoryTrack's static members.
159  *
160  * *All* files that use MemoryTrack will instantiate a static
161  * instance of this class (see static instance below).
162  *
163  * This class counts how many static instantiations have happened so
164  * far, making sure to init/destroy MemoryTrack's static members only once.
165  *
166  * Adapted from:
167  * http://www.hlrs.de/organization/par/services/tools/docu/kcc/
168  *       tutorials/static_initialization.html
169  */
170 class MemoryTrackStaticInitCounter {
171 
172 
173     public:
174 
175 
176 
MemoryTrackStaticInitCounter()177         MemoryTrackStaticInitCounter() {
178             if( mCount == 0 ) {
179                 // allocate static members
180                 MemoryTrack::mLock = new MutexLock();
181 
182                 MemoryTrack::mListHead =
183                     (AllocationList *)
184                         malloc( sizeof( AllocationList ) );
185                 MemoryTrack::mListHead->mPrevious = NULL;
186                 MemoryTrack::mListHead->mNext = NULL;
187 
188                 MemoryTrack::mTotalAllocationSize = 0;
189                 MemoryTrack::mTotalDeallocationSize = 0;
190                 MemoryTrack::mNumberOfAllocations = 0;
191 
192                 MemoryTrack::mTracking = true;
193                 }
194             mCount++;
195             }
196 
197 
198 
~MemoryTrackStaticInitCounter()199         ~MemoryTrackStaticInitCounter() {
200             mCount--;
201             if( mCount == 0 ) {
202                 // print leaks... we should only get here after
203                 // all static members of classes that use MemoryTrack
204                 // have been destroyed.
205                 MemoryTrack::printLeaks();
206 
207                 MemoryTrack::mTracking = false;
208                 // deallocate static members
209                 free( MemoryTrack::mListHead );
210                 delete MemoryTrack::mLock;
211                 }
212             }
213 
214 
215     private:
216         // only allocate/deallocate when mCount == 0
217         static int mCount;
218 
219     };
220 
221 
222 
223 // This will be included in *every* file that includes MemoryTrack.h
224 static MemoryTrackStaticInitCounter memoryTrackInitializer;
225 
226 
227 
228 #endif
229 
230 
231