NetBurner 3.1
MemoryLeakDetector.h
1 /*
2  * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the <organization> nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef D_MemoryLeakDetector_h
29 #define D_MemoryLeakDetector_h
30 
31 enum MemLeakPeriod
32 {
33  mem_leak_period_all,
34  mem_leak_period_disabled,
35  mem_leak_period_enabled,
36  mem_leak_period_checking
37 };
38 
39 class TestMemoryAllocator;
40 class SimpleMutex;
41 
42 class MemoryLeakFailure
43 {
44 public:
45  virtual ~MemoryLeakFailure()
46  {
47  }
48 
49  virtual void fail(char* fail_string)=0;
50 };
51 
52 struct SimpleStringBuffer
53 {
54  enum
55  {
56  SIMPLE_STRING_BUFFER_LEN = 4096
57  };
58 
59  SimpleStringBuffer();
60  void clear();
61  void add(const char* format, ...) __check_format__(printf, 2, 3);
62  void addMemoryDump(const void* memory, size_t memorySize);
63 
64  char* toString();
65 
66  void setWriteLimit(size_t write_limit);
67  void resetWriteLimit();
68  bool reachedItsCapacity();
69 private:
70  char buffer_[SIMPLE_STRING_BUFFER_LEN];
71  size_t positions_filled_;
72  size_t write_limit_;
73 };
74 
75 struct MemoryLeakDetectorNode;
76 
77 class MemoryLeakOutputStringBuffer
78 {
79 public:
80  MemoryLeakOutputStringBuffer();
81 
82  void clear();
83 
84  void startMemoryLeakReporting();
85  void stopMemoryLeakReporting();
86 
87  void reportMemoryLeak(MemoryLeakDetectorNode* leak);
88 
89  void reportDeallocateNonAllocatedMemoryFailure(const char* freeFile, int freeLine, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter);
90  void reportMemoryCorruptionFailure(MemoryLeakDetectorNode* node, const char* freeFile, int freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter);
91  void reportAllocationDeallocationMismatchFailure(MemoryLeakDetectorNode* node, const char* freeFile, int freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter);
92  char* toString();
93 
94 private:
95  void addAllocationLocation(const char* allocationFile, int allocationLineNumber, size_t allocationSize, TestMemoryAllocator* allocator);
96  void addDeallocationLocation(const char* freeFile, int freeLineNumber, TestMemoryAllocator* allocator);
97 
98  void addMemoryLeakHeader();
99  void addMemoryLeakFooter(int totalAmountOfLeaks);
100  void addWarningForUsingMalloc();
101  void addNoMemoryLeaksMessage();
102  void addErrorMessageForTooMuchLeaks();
103 
104 private:
105 
106  int total_leaks_;
107  bool giveWarningOnUsingMalloc_;
108 
109  void reportFailure(const char* message, const char* allocFile,
110  int allocLine, size_t allocSize,
111  TestMemoryAllocator* allocAllocator, const char* freeFile,
112  int freeLine, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter);
113 
114  SimpleStringBuffer outputBuffer_;
115 };
116 
117 struct MemoryLeakDetectorNode
118 {
119  MemoryLeakDetectorNode() :
120  size_(0), number_(0), memory_(0), file_(0), line_(0), allocator_(0), period_(mem_leak_period_enabled), next_(0)
121  {
122  }
123 
124  void init(char* memory, unsigned number, size_t size, TestMemoryAllocator* allocator, MemLeakPeriod period, const char* file, int line);
125 
126  size_t size_;
127  unsigned number_;
128  char* memory_;
129  const char* file_;
130  int line_;
131  TestMemoryAllocator* allocator_;
132  MemLeakPeriod period_;
133 
134 private:
135  friend struct MemoryLeakDetectorList;
136  MemoryLeakDetectorNode* next_;
137 };
138 
139 struct MemoryLeakDetectorList
140 {
141  MemoryLeakDetectorList() :
142  head_(0)
143  {}
144 
145  void addNewNode(MemoryLeakDetectorNode* node);
146  MemoryLeakDetectorNode* retrieveNode(char* memory);
147  MemoryLeakDetectorNode* removeNode(char* memory);
148 
149  MemoryLeakDetectorNode* getFirstLeak(MemLeakPeriod period);
150  MemoryLeakDetectorNode* getNextLeak(MemoryLeakDetectorNode* node,
151  MemLeakPeriod period);
152  MemoryLeakDetectorNode* getLeakFrom(MemoryLeakDetectorNode* node,
153  MemLeakPeriod period);
154 
155  int getTotalLeaks(MemLeakPeriod period);
156  void clearAllAccounting(MemLeakPeriod period);
157 
158  bool isInPeriod(MemoryLeakDetectorNode* node, MemLeakPeriod period);
159 
160 private:
161  MemoryLeakDetectorNode* head_;
162 };
163 
164 struct MemoryLeakDetectorTable
165 {
166  void clearAllAccounting(MemLeakPeriod period);
167 
168  void addNewNode(MemoryLeakDetectorNode* node);
169  MemoryLeakDetectorNode* retrieveNode(char* memory);
170  MemoryLeakDetectorNode* removeNode(char* memory);
171 
172  int getTotalLeaks(MemLeakPeriod period);
173 
174  MemoryLeakDetectorNode* getFirstLeak(MemLeakPeriod period);
175  MemoryLeakDetectorNode* getNextLeak(MemoryLeakDetectorNode* leak,
176  MemLeakPeriod period);
177 
178 private:
179  unsigned long hash(char* memory);
180 
181  enum
182  {
183  hash_prime = MEMORY_LEAK_HASH_TABLE_SIZE
184  };
185  MemoryLeakDetectorList table_[hash_prime];
186 };
187 
188 class MemoryLeakDetector
189 {
190 public:
191  MemoryLeakDetector(MemoryLeakFailure* reporter);
192  virtual ~MemoryLeakDetector();
193 
194  void enable();
195  void disable();
196 
197  void disableAllocationTypeChecking();
198  void enableAllocationTypeChecking();
199 
200  void startChecking();
201  void stopChecking();
202 
203  const char* report(MemLeakPeriod period);
204  void markCheckingPeriodLeaksAsNonCheckingPeriod();
205  int totalMemoryLeaks(MemLeakPeriod period);
206  void clearAllAccounting(MemLeakPeriod period);
207 
208  char* allocMemory(TestMemoryAllocator* allocator, size_t size, bool allocatNodesSeperately = false);
209  char* allocMemory(TestMemoryAllocator* allocator, size_t size,
210  const char* file, int line, bool allocatNodesSeperately = false);
211  void deallocMemory(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately = false);
212  void deallocMemory(TestMemoryAllocator* allocator, void* memory, const char* file, int line, bool allocatNodesSeperately = false);
213  char* reallocMemory(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately = false);
214 
215  void invalidateMemory(char* memory);
216  void removeMemoryLeakInformationWithoutCheckingOrDeallocatingTheMemoryButDeallocatingTheAccountInformation(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately);
217  enum
218  {
219  memory_corruption_buffer_size = 3
220  };
221 
222  unsigned getCurrentAllocationNumber();
223 
224  SimpleMutex* getMutex(void);
225 private:
226  MemoryLeakFailure* reporter_;
227  MemLeakPeriod current_period_;
228  MemoryLeakOutputStringBuffer outputBuffer_;
229  MemoryLeakDetectorTable memoryTable_;
230  bool doAllocationTypeChecking_;
231  unsigned allocationSequenceNumber_;
232  SimpleMutex* mutex_;
233 
234  char* allocateMemoryWithAccountingInformation(TestMemoryAllocator* allocator, size_t size, const char* file, int line, bool allocatNodesSeperately);
235  char* reallocateMemoryWithAccountingInformation(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately);
236  MemoryLeakDetectorNode* createMemoryLeakAccountingInformation(TestMemoryAllocator* allocator, size_t size, char* memory, bool allocatNodesSeperately);
237 
238 
239  bool validMemoryCorruptionInformation(char* memory);
240  bool matchingAllocation(TestMemoryAllocator *alloc_allocator, TestMemoryAllocator *free_allocator);
241 
242  void storeLeakInformation(MemoryLeakDetectorNode * node, char *new_memory, size_t size, TestMemoryAllocator *allocator, const char *file, int line);
243  void ConstructMemoryLeakReport(MemLeakPeriod period);
244 
245  size_t sizeOfMemoryWithCorruptionInfo(size_t size);
246  MemoryLeakDetectorNode* getNodeFromMemoryPointer(char* memory, size_t size);
247 
248  char* reallocateMemoryAndLeakInformation(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately);
249 
250  void addMemoryCorruptionInformation(char* memory);
251  void checkForCorruption(MemoryLeakDetectorNode* node, const char* file, int line, TestMemoryAllocator* allocator, bool allocateNodesSeperately);
252 };
253 
254 #endif
void init()
System initialization. Normally called at the beginning of all applications.
Definition: init.cpp:22