fork
Fork of cpputest by
Embed:
(wiki syntax)
Show/hide line numbers
MemoryLeakDetector.cpp
00001 /* 00002 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * * Redistributions of source code must retain the above copyright 00008 * notice, this list of conditions and the following disclaimer. 00009 * * Redistributions in binary form must reproduce the above copyright 00010 * notice, this list of conditions and the following disclaimer in the 00011 * documentation and/or other materials provided with the distribution. 00012 * * Neither the name of the <organization> nor the 00013 * names of its contributors may be used to endorse or promote products 00014 * derived from this software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY 00017 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00018 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY 00020 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00021 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00022 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00023 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00025 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 #include "CppUTest/TestHarness.h" 00028 #include "CppUTest/MemoryLeakDetector.h" 00029 #include "CppUTest/TestMemoryAllocator.h" 00030 #include "CppUTest/PlatformSpecificFunctions.h" 00031 00032 #define UNKNOWN ((char*)("<unknown>")) 00033 00034 SimpleStringBuffer::SimpleStringBuffer() : 00035 positions_filled_(0), write_limit_(SIMPLE_STRING_BUFFER_LEN-1) 00036 { 00037 } 00038 00039 void SimpleStringBuffer::clear() 00040 { 00041 positions_filled_ = 0; 00042 buffer_[0] = '\0'; 00043 } 00044 00045 void SimpleStringBuffer::add(const char* format, ...) 00046 { 00047 int count = 0; 00048 size_t positions_left = write_limit_ - positions_filled_; 00049 if (positions_left <= 0) return; 00050 00051 va_list arguments; 00052 va_start(arguments, format); 00053 count = PlatformSpecificVSNprintf(buffer_ + positions_filled_, positions_left+1, format, arguments); 00054 if (count > 0) positions_filled_ += (size_t) count; 00055 if (positions_filled_ > write_limit_) positions_filled_ = write_limit_; 00056 va_end(arguments); 00057 } 00058 00059 char* SimpleStringBuffer::toString() 00060 { 00061 return buffer_; 00062 } 00063 00064 void SimpleStringBuffer::setWriteLimit(size_t write_limit) 00065 { 00066 write_limit_ = write_limit; 00067 if (write_limit_ > SIMPLE_STRING_BUFFER_LEN-1) 00068 write_limit_ = SIMPLE_STRING_BUFFER_LEN-1; 00069 } 00070 void SimpleStringBuffer::resetWriteLimit() 00071 { 00072 write_limit_ = SIMPLE_STRING_BUFFER_LEN-1; 00073 } 00074 00075 bool SimpleStringBuffer::reachedItsCapacity() 00076 { 00077 return positions_filled_ >= write_limit_; 00078 } 00079 00080 //////////////////////// 00081 00082 #define MEM_LEAK_TOO_MUCH "\netc etc etc etc. !!!! Too much memory leaks to report. Bailing out\n" 00083 #define MEM_LEAK_FOOTER "Total number of leaks: " 00084 #define MEM_LEAK_ADDITION_MALLOC_WARNING "NOTE:\n" \ 00085 "\tMemory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc,\n" \ 00086 "\tbut deallocate using the standard free.\n" \ 00087 "\tIf this is the case, check whether your malloc/free replacements are working (#define malloc cpputest_malloc etc).\n" 00088 00089 MemoryLeakOutputStringBuffer::MemoryLeakOutputStringBuffer() 00090 : total_leaks_(0), giveWarningOnUsingMalloc_(false) 00091 { 00092 } 00093 00094 void MemoryLeakOutputStringBuffer::addAllocationLocation(const char* allocationFile, int allocationLineNumber, size_t allocationSize, TestMemoryAllocator* allocator) 00095 { 00096 outputBuffer_.add(" allocated at file: %s line: %d size: %lu type: %s\n", allocationFile, allocationLineNumber, (unsigned long) allocationSize, allocator->alloc_name()); 00097 } 00098 00099 void MemoryLeakOutputStringBuffer::addDeallocationLocation(const char* freeFile, int freeLineNumber, TestMemoryAllocator* allocator) 00100 { 00101 outputBuffer_.add(" deallocated at file: %s line: %d type: %s\n", freeFile, freeLineNumber, allocator->free_name()); 00102 } 00103 00104 void MemoryLeakOutputStringBuffer::addNoMemoryLeaksMessage() 00105 { 00106 outputBuffer_.add("No memory leaks were detected."); 00107 } 00108 00109 void MemoryLeakOutputStringBuffer::startMemoryLeakReporting() 00110 { 00111 giveWarningOnUsingMalloc_ = false; 00112 total_leaks_ = 0; 00113 00114 size_t memory_leak_normal_footer_size = sizeof(MEM_LEAK_FOOTER) + 10 + sizeof(MEM_LEAK_TOO_MUCH); /* the number of leaks */ 00115 size_t memory_leak_foot_size_with_malloc_warning = memory_leak_normal_footer_size + sizeof(MEM_LEAK_ADDITION_MALLOC_WARNING); 00116 00117 outputBuffer_.setWriteLimit(SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN - memory_leak_foot_size_with_malloc_warning); 00118 } 00119 00120 void MemoryLeakOutputStringBuffer::reportMemoryLeak(MemoryLeakDetectorNode* leak) 00121 { 00122 if (total_leaks_ == 0) { 00123 addMemoryLeakHeader(); 00124 } 00125 00126 total_leaks_++; 00127 outputBuffer_.add("Alloc num (%u) Leak size: %lu Allocated at: %s and line: %d. Type: \"%s\"\n\t Memory: <%p> Content: \"%.15s\"\n", 00128 leak->number_, (unsigned long) leak->size_, leak->file_, leak->line_, leak->allocator_->alloc_name(), leak->memory_, leak->memory_); 00129 00130 if (PlatformSpecificStrCmp(leak->allocator_->alloc_name(), "malloc") == 0) 00131 giveWarningOnUsingMalloc_ = true; 00132 } 00133 00134 void MemoryLeakOutputStringBuffer::stopMemoryLeakReporting() 00135 { 00136 if (total_leaks_ == 0) { 00137 addNoMemoryLeaksMessage(); 00138 return; 00139 } 00140 00141 bool buffer_reached_its_capacity = outputBuffer_.reachedItsCapacity(); 00142 outputBuffer_.resetWriteLimit(); 00143 00144 if (buffer_reached_its_capacity) 00145 addErrorMessageForTooMuchLeaks(); 00146 00147 addMemoryLeakFooter(total_leaks_); 00148 00149 if (giveWarningOnUsingMalloc_) 00150 addWarningForUsingMalloc(); 00151 00152 } 00153 00154 void MemoryLeakOutputStringBuffer::addMemoryLeakHeader() 00155 { 00156 outputBuffer_.add("Memory leak(s) found.\n"); 00157 } 00158 00159 void MemoryLeakOutputStringBuffer::addErrorMessageForTooMuchLeaks() 00160 { 00161 outputBuffer_.add(MEM_LEAK_TOO_MUCH); 00162 } 00163 00164 void MemoryLeakOutputStringBuffer::addMemoryLeakFooter(int amountOfLeaks) 00165 { 00166 outputBuffer_.add("%s %d\n", MEM_LEAK_FOOTER, amountOfLeaks); 00167 } 00168 00169 void MemoryLeakOutputStringBuffer::addWarningForUsingMalloc() 00170 { 00171 outputBuffer_.add(MEM_LEAK_ADDITION_MALLOC_WARNING); 00172 } 00173 00174 void MemoryLeakOutputStringBuffer::reportDeallocateNonAllocatedMemoryFailure(const char* freeFile, int freeLine, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) 00175 { 00176 reportFailure("Deallocating non-allocated memory\n", "<unknown>", 0, 0, NullUnknownAllocator::defaultAllocator(), freeFile, freeLine, freeAllocator, reporter); 00177 } 00178 00179 void MemoryLeakOutputStringBuffer::reportAllocationDeallocationMismatchFailure(MemoryLeakDetectorNode* node, const char* freeFile, int freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) 00180 { 00181 reportFailure("Allocation/deallocation type mismatch\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter); 00182 } 00183 00184 void MemoryLeakOutputStringBuffer::reportMemoryCorruptionFailure(MemoryLeakDetectorNode* node, const char* freeFile, int freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) 00185 { 00186 reportFailure("Memory corruption (written out of bounds?)\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter); 00187 } 00188 00189 void MemoryLeakOutputStringBuffer::reportFailure(const char* message, const char* allocFile, int allocLine, size_t allocSize, TestMemoryAllocator* allocAllocator, const char* freeFile, int freeLine, 00190 TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) 00191 { 00192 outputBuffer_.add("%s", message); 00193 addAllocationLocation(allocFile, allocLine, allocSize, allocAllocator); 00194 addDeallocationLocation(freeFile, freeLine, freeAllocator); 00195 reporter->fail(toString()); 00196 } 00197 00198 00199 char* MemoryLeakOutputStringBuffer::toString() 00200 { 00201 return outputBuffer_.toString(); 00202 } 00203 00204 void MemoryLeakOutputStringBuffer::clear() 00205 { 00206 outputBuffer_.clear(); 00207 } 00208 00209 //////////////////////// 00210 00211 void MemoryLeakDetectorNode::init(char* memory, unsigned number, size_t size, TestMemoryAllocator* allocator, MemLeakPeriod period, const char* file, int line) 00212 { 00213 number_ = number; 00214 memory_ = memory; 00215 size_ = size; 00216 allocator_ = allocator; 00217 period_ = period; 00218 file_ = file; 00219 line_ = line; 00220 } 00221 00222 /////////////////////// 00223 00224 bool MemoryLeakDetectorList::isInPeriod(MemoryLeakDetectorNode* node, MemLeakPeriod period) 00225 { 00226 return period == mem_leak_period_all || node->period_ == period || (node->period_ != mem_leak_period_disabled && period == mem_leak_period_enabled); 00227 } 00228 00229 void MemoryLeakDetectorList::clearAllAccounting(MemLeakPeriod period) 00230 { 00231 MemoryLeakDetectorNode* cur = head_; 00232 MemoryLeakDetectorNode* prev = 0; 00233 00234 while (cur) { 00235 if (isInPeriod(cur, period)) { 00236 if (prev) { 00237 prev->next_ = cur->next_; 00238 cur = prev; 00239 } 00240 else { 00241 head_ = cur->next_; 00242 cur = head_; 00243 continue; 00244 } 00245 } 00246 prev = cur; 00247 cur = cur->next_; 00248 } 00249 } 00250 00251 void MemoryLeakDetectorList::addNewNode(MemoryLeakDetectorNode* node) 00252 { 00253 node->next_ = head_; 00254 head_ = node; 00255 } 00256 00257 MemoryLeakDetectorNode* MemoryLeakDetectorList::removeNode(char* memory) 00258 { 00259 MemoryLeakDetectorNode* cur = head_; 00260 MemoryLeakDetectorNode* prev = 0; 00261 while (cur) { 00262 if (cur->memory_ == memory) { 00263 if (prev) { 00264 prev->next_ = cur->next_; 00265 return cur; 00266 } 00267 else { 00268 head_ = cur->next_; 00269 return cur; 00270 } 00271 } 00272 prev = cur; 00273 cur = cur->next_; 00274 } 00275 return 0; 00276 } 00277 00278 MemoryLeakDetectorNode* MemoryLeakDetectorList::retrieveNode(char* memory) 00279 { 00280 MemoryLeakDetectorNode* cur = head_; 00281 while (cur) { 00282 if (cur->memory_ == memory) 00283 return cur; 00284 cur = cur->next_; 00285 } 00286 return NULL; 00287 } 00288 00289 MemoryLeakDetectorNode* MemoryLeakDetectorList::getLeakFrom(MemoryLeakDetectorNode* node, MemLeakPeriod period) 00290 { 00291 for (MemoryLeakDetectorNode* cur = node; cur; cur = cur->next_) 00292 if (isInPeriod(cur, period)) return cur; 00293 return 0; 00294 } 00295 00296 MemoryLeakDetectorNode* MemoryLeakDetectorList::getFirstLeak(MemLeakPeriod period) 00297 { 00298 return getLeakFrom(head_, period); 00299 } 00300 00301 MemoryLeakDetectorNode* MemoryLeakDetectorList::getNextLeak(MemoryLeakDetectorNode* node, MemLeakPeriod period) 00302 { 00303 return getLeakFrom(node->next_, period); 00304 } 00305 00306 int MemoryLeakDetectorList::getTotalLeaks(MemLeakPeriod period) 00307 { 00308 int total_leaks = 0; 00309 for (MemoryLeakDetectorNode* node = head_; node; node = node->next_) { 00310 if (isInPeriod(node, period)) total_leaks++; 00311 } 00312 return total_leaks; 00313 } 00314 00315 bool MemoryLeakDetectorList::hasLeaks(MemLeakPeriod period) 00316 { 00317 for (MemoryLeakDetectorNode* node = head_; node; node = node->next_) 00318 if (isInPeriod(node, period)) return true; 00319 return false; 00320 } 00321 00322 ///////////////////////////////////////////////////////////// 00323 00324 unsigned long MemoryLeakDetectorTable::hash(char* memory) 00325 { 00326 return (unsigned long)((size_t)memory % hash_prime); 00327 } 00328 00329 void MemoryLeakDetectorTable::clearAllAccounting(MemLeakPeriod period) 00330 { 00331 for (int i = 0; i < hash_prime; i++) 00332 table_[i].clearAllAccounting(period); 00333 } 00334 00335 void MemoryLeakDetectorTable::addNewNode(MemoryLeakDetectorNode* node) 00336 { 00337 table_[hash(node->memory_)].addNewNode(node); 00338 } 00339 00340 MemoryLeakDetectorNode* MemoryLeakDetectorTable::removeNode(char* memory) 00341 { 00342 return table_[hash(memory)].removeNode(memory); 00343 } 00344 00345 MemoryLeakDetectorNode* MemoryLeakDetectorTable::retrieveNode(char* memory) 00346 { 00347 return table_[hash(memory)].retrieveNode(memory); 00348 } 00349 00350 bool MemoryLeakDetectorTable::hasLeaks(MemLeakPeriod period) 00351 { 00352 for (int i = 0; i < hash_prime; i++) 00353 if (table_[i].hasLeaks(period)) return true; 00354 return false; 00355 } 00356 00357 int MemoryLeakDetectorTable::getTotalLeaks(MemLeakPeriod period) 00358 { 00359 int total_leaks = 0; 00360 for (int i = 0; i < hash_prime; i++) 00361 total_leaks += table_[i].getTotalLeaks(period); 00362 return total_leaks; 00363 } 00364 00365 MemoryLeakDetectorNode* MemoryLeakDetectorTable::getFirstLeak(MemLeakPeriod period) 00366 { 00367 for (int i = 0; i < hash_prime; i++) { 00368 MemoryLeakDetectorNode* node = table_[i].getFirstLeak(period); 00369 if (node) return node; 00370 } 00371 return 0; 00372 } 00373 00374 MemoryLeakDetectorNode* MemoryLeakDetectorTable::getNextLeak(MemoryLeakDetectorNode* leak, MemLeakPeriod period) 00375 { 00376 unsigned long i = hash(leak->memory_); 00377 MemoryLeakDetectorNode* node = table_[i].getNextLeak(leak, period); 00378 if (node) return node; 00379 00380 for (++i; i < hash_prime; i++) { 00381 node = table_[i].getFirstLeak(period); 00382 if (node) return node; 00383 } 00384 return 0; 00385 } 00386 00387 ///////////////////////////////////////////////////////////// 00388 00389 MemoryLeakDetector::MemoryLeakDetector(MemoryLeakFailure* reporter) 00390 { 00391 doAllocationTypeChecking_ = true; 00392 allocationSequenceNumber_ = 1; 00393 current_period_ = mem_leak_period_disabled; 00394 reporter_ = reporter; 00395 outputBuffer_ = MemoryLeakOutputStringBuffer(); 00396 memoryTable_ = MemoryLeakDetectorTable(); 00397 } 00398 00399 void MemoryLeakDetector::clearAllAccounting(MemLeakPeriod period) 00400 { 00401 memoryTable_.clearAllAccounting(period); 00402 } 00403 00404 void MemoryLeakDetector::startChecking() 00405 { 00406 outputBuffer_.clear(); 00407 current_period_ = mem_leak_period_checking; 00408 } 00409 00410 void MemoryLeakDetector::stopChecking() 00411 { 00412 current_period_ = mem_leak_period_enabled; 00413 } 00414 00415 void MemoryLeakDetector::enable() 00416 { 00417 current_period_ = mem_leak_period_enabled; 00418 } 00419 00420 void MemoryLeakDetector::disable() 00421 { 00422 current_period_ = mem_leak_period_disabled; 00423 } 00424 00425 void MemoryLeakDetector::disableAllocationTypeChecking() 00426 { 00427 doAllocationTypeChecking_ = false; 00428 } 00429 00430 void MemoryLeakDetector::enableAllocationTypeChecking() 00431 { 00432 doAllocationTypeChecking_ = true; 00433 } 00434 00435 unsigned MemoryLeakDetector::getCurrentAllocationNumber() 00436 { 00437 return allocationSequenceNumber_; 00438 } 00439 00440 static size_t calculateVoidPointerAlignedSize(size_t size) 00441 { 00442 return (sizeof(void*) - (size % sizeof(void*))) + size; 00443 } 00444 00445 size_t MemoryLeakDetector::sizeOfMemoryWithCorruptionInfo(size_t size) 00446 { 00447 return calculateVoidPointerAlignedSize(size + memory_corruption_buffer_size); 00448 } 00449 00450 MemoryLeakDetectorNode* MemoryLeakDetector::getNodeFromMemoryPointer(char* memory, size_t memory_size) 00451 { 00452 return (MemoryLeakDetectorNode*) (void*) (memory + sizeOfMemoryWithCorruptionInfo(memory_size)); 00453 } 00454 00455 void MemoryLeakDetector::storeLeakInformation(MemoryLeakDetectorNode * node, char *new_memory, size_t size, TestMemoryAllocator *allocator, const char *file, int line) 00456 { 00457 node->init(new_memory, allocationSequenceNumber_++, size, allocator, current_period_, file, line); 00458 addMemoryCorruptionInformation(node->memory_ + node->size_); 00459 memoryTable_.addNewNode(node); 00460 } 00461 00462 char* MemoryLeakDetector::reallocateMemoryAndLeakInformation(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately) 00463 { 00464 char* new_memory = reallocateMemoryWithAccountingInformation(allocator, memory, size, file, line, allocatNodesSeperately); 00465 if (new_memory == NULL) return NULL; 00466 00467 MemoryLeakDetectorNode *node = createMemoryLeakAccountingInformation(allocator, size, new_memory, allocatNodesSeperately); 00468 storeLeakInformation(node, new_memory, size, allocator, file, line); 00469 return node->memory_; 00470 } 00471 00472 void MemoryLeakDetector::invalidateMemory(char* memory) 00473 { 00474 MemoryLeakDetectorNode* node = memoryTable_.retrieveNode(memory); 00475 if (node) 00476 PlatformSpecificMemset(memory, 0xCD, node->size_); 00477 } 00478 00479 void MemoryLeakDetector::addMemoryCorruptionInformation(char* memory) 00480 { 00481 memory[0] = 'B'; 00482 memory[1] = 'A'; 00483 memory[2] = 'S'; 00484 } 00485 00486 bool MemoryLeakDetector::validMemoryCorruptionInformation(char* memory) 00487 { 00488 return memory[0] == 'B' && memory[1] == 'A' && memory[2] == 'S'; 00489 } 00490 00491 bool MemoryLeakDetector::matchingAllocation(TestMemoryAllocator *alloc_allocator, TestMemoryAllocator *free_allocator) 00492 { 00493 if (alloc_allocator == free_allocator) return true; 00494 if (!doAllocationTypeChecking_) return true; 00495 return free_allocator->isOfEqualType(alloc_allocator); 00496 } 00497 00498 void MemoryLeakDetector::checkForCorruption(MemoryLeakDetectorNode* node, const char* file, int line, TestMemoryAllocator* allocator, bool allocateNodesSeperately) 00499 { 00500 if (!matchingAllocation(node->allocator_, allocator)) 00501 outputBuffer_.reportAllocationDeallocationMismatchFailure(node, file, line, allocator, reporter_); 00502 else if (!validMemoryCorruptionInformation(node->memory_ + node->size_)) 00503 outputBuffer_.reportMemoryCorruptionFailure(node, file, line, allocator, reporter_); 00504 else if (allocateNodesSeperately) 00505 allocator->freeMemoryLeakNode((char*) node); 00506 } 00507 00508 char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, bool allocatNodesSeperately) 00509 { 00510 return allocMemory(allocator, size, UNKNOWN, 0, allocatNodesSeperately); 00511 } 00512 00513 char* MemoryLeakDetector::allocateMemoryWithAccountingInformation(TestMemoryAllocator* allocator, size_t size, const char* file, int line, bool allocatNodesSeperately) 00514 { 00515 if (allocatNodesSeperately) return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size), file, line); 00516 else return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode), file, line); 00517 } 00518 00519 char* MemoryLeakDetector::reallocateMemoryWithAccountingInformation(TestMemoryAllocator* /*allocator*/, char* memory, size_t size, const char* /*file*/, int /*line*/, bool allocatNodesSeperately) 00520 { 00521 if (allocatNodesSeperately) return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size)); 00522 else return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode)); 00523 } 00524 00525 MemoryLeakDetectorNode* MemoryLeakDetector::createMemoryLeakAccountingInformation(TestMemoryAllocator* allocator, size_t size, char* memory, bool allocatNodesSeperately) 00526 { 00527 if (allocatNodesSeperately) return (MemoryLeakDetectorNode*) (void*) allocator->allocMemoryLeakNode(sizeof(MemoryLeakDetectorNode)); 00528 else return getNodeFromMemoryPointer(memory, size); 00529 } 00530 00531 char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, const char* file, int line, bool allocatNodesSeperately) 00532 { 00533 /* With malloc, it is harder to guarantee that the allocator free is called. 00534 * This is because operator new is overloaded via linker symbols, but malloc just via #defines. 00535 * If the same allocation is used and the wrong free is called, it will deallocate the memory leak information 00536 * without the memory leak detector ever noticing it! 00537 * So, for malloc, we'll allocate the memory separately so we can detect this and give a proper error. 00538 */ 00539 00540 char* memory = allocateMemoryWithAccountingInformation(allocator, size, file, line, allocatNodesSeperately); 00541 if (memory == NULL) return NULL; 00542 MemoryLeakDetectorNode* node = createMemoryLeakAccountingInformation(allocator, size, memory, allocatNodesSeperately); 00543 00544 storeLeakInformation(node, memory, size, allocator, file, line); 00545 return node->memory_; 00546 } 00547 00548 void MemoryLeakDetector::removeMemoryLeakInformationWithoutCheckingOrDeallocatingTheMemoryButDeallocatingTheAccountInformation(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately) 00549 { 00550 MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory); 00551 if (allocatNodesSeperately) allocator->freeMemoryLeakNode( (char*) node); 00552 } 00553 00554 void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, const char* file, int line, bool allocatNodesSeperately) 00555 { 00556 if (memory == 0) return; 00557 00558 MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory); 00559 if (node == NULL) { 00560 outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_); 00561 return; 00562 } 00563 if (!allocator->hasBeenDestroyed()) { 00564 checkForCorruption(node, file, line, allocator, allocatNodesSeperately); 00565 allocator->free_memory((char*) memory, file, line); 00566 } 00567 } 00568 00569 void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately) 00570 { 00571 deallocMemory(allocator, (char*) memory, UNKNOWN, 0, allocatNodesSeperately); 00572 } 00573 00574 char* MemoryLeakDetector::reallocMemory(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately) 00575 { 00576 if (memory) { 00577 MemoryLeakDetectorNode* node = memoryTable_.removeNode(memory); 00578 if (node == NULL) { 00579 outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_); 00580 return NULL; 00581 } 00582 checkForCorruption(node, file, line, allocator, allocatNodesSeperately); 00583 } 00584 return reallocateMemoryAndLeakInformation(allocator, memory, size, file, line, allocatNodesSeperately); 00585 } 00586 00587 void MemoryLeakDetector::ConstructMemoryLeakReport(MemLeakPeriod period) 00588 { 00589 MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(period); 00590 00591 outputBuffer_.startMemoryLeakReporting(); 00592 00593 while (leak) { 00594 outputBuffer_.reportMemoryLeak(leak); 00595 leak = memoryTable_.getNextLeak(leak, period); 00596 } 00597 00598 outputBuffer_.stopMemoryLeakReporting(); 00599 } 00600 00601 const char* MemoryLeakDetector::report(MemLeakPeriod period) 00602 { 00603 outputBuffer_.clear(); 00604 ConstructMemoryLeakReport(period); 00605 00606 return outputBuffer_.toString(); 00607 } 00608 00609 void MemoryLeakDetector::markCheckingPeriodLeaksAsNonCheckingPeriod() 00610 { 00611 MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(mem_leak_period_checking); 00612 while (leak) { 00613 if (leak->period_ == mem_leak_period_checking) leak->period_ = mem_leak_period_enabled; 00614 leak = memoryTable_.getNextLeak(leak, mem_leak_period_checking); 00615 } 00616 } 00617 00618 int MemoryLeakDetector::totalMemoryLeaks(MemLeakPeriod period) 00619 { 00620 return memoryTable_.getTotalLeaks(period); 00621 }
Generated on Tue Jul 12 2022 21:37:56 by 1.7.2