fork

Fork of cpputest by Rohit Grover

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MemoryLeakDetector.cpp Source File

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 }