fork
Fork of cpputest by
src/CppUTest/MemoryLeakDetector.cpp@0:0b799af9d58e, 2014-01-28 (annotated)
- Committer:
- rgrover1
- Date:
- Tue Jan 28 09:27:41 2014 +0000
- Revision:
- 0:0b799af9d58e
- Child:
- 1:4769360130ed
CppUTest unit test framework.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rgrover1 | 0:0b799af9d58e | 1 | /* |
rgrover1 | 0:0b799af9d58e | 2 | * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde |
rgrover1 | 0:0b799af9d58e | 3 | * All rights reserved. |
rgrover1 | 0:0b799af9d58e | 4 | * |
rgrover1 | 0:0b799af9d58e | 5 | * Redistribution and use in source and binary forms, with or without |
rgrover1 | 0:0b799af9d58e | 6 | * modification, are permitted provided that the following conditions are met: |
rgrover1 | 0:0b799af9d58e | 7 | * * Redistributions of source code must retain the above copyright |
rgrover1 | 0:0b799af9d58e | 8 | * notice, this list of conditions and the following disclaimer. |
rgrover1 | 0:0b799af9d58e | 9 | * * Redistributions in binary form must reproduce the above copyright |
rgrover1 | 0:0b799af9d58e | 10 | * notice, this list of conditions and the following disclaimer in the |
rgrover1 | 0:0b799af9d58e | 11 | * documentation and/or other materials provided with the distribution. |
rgrover1 | 0:0b799af9d58e | 12 | * * Neither the name of the <organization> nor the |
rgrover1 | 0:0b799af9d58e | 13 | * names of its contributors may be used to endorse or promote products |
rgrover1 | 0:0b799af9d58e | 14 | * derived from this software without specific prior written permission. |
rgrover1 | 0:0b799af9d58e | 15 | * |
rgrover1 | 0:0b799af9d58e | 16 | * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY |
rgrover1 | 0:0b799af9d58e | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
rgrover1 | 0:0b799af9d58e | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
rgrover1 | 0:0b799af9d58e | 19 | * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY |
rgrover1 | 0:0b799af9d58e | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
rgrover1 | 0:0b799af9d58e | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
rgrover1 | 0:0b799af9d58e | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
rgrover1 | 0:0b799af9d58e | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
rgrover1 | 0:0b799af9d58e | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
rgrover1 | 0:0b799af9d58e | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
rgrover1 | 0:0b799af9d58e | 26 | */ |
rgrover1 | 0:0b799af9d58e | 27 | #include "CppUTest/TestHarness.h" |
rgrover1 | 0:0b799af9d58e | 28 | #include "CppUTest/MemoryLeakDetector.h" |
rgrover1 | 0:0b799af9d58e | 29 | #include "CppUTest/TestMemoryAllocator.h" |
rgrover1 | 0:0b799af9d58e | 30 | #include "CppUTest/PlatformSpecificFunctions.h" |
rgrover1 | 0:0b799af9d58e | 31 | |
rgrover1 | 0:0b799af9d58e | 32 | #define UNKNOWN ((char*)("<unknown>")) |
rgrover1 | 0:0b799af9d58e | 33 | |
rgrover1 | 0:0b799af9d58e | 34 | SimpleStringBuffer::SimpleStringBuffer() : |
rgrover1 | 0:0b799af9d58e | 35 | positions_filled_(0), write_limit_(SIMPLE_STRING_BUFFER_LEN-1) |
rgrover1 | 0:0b799af9d58e | 36 | { |
rgrover1 | 0:0b799af9d58e | 37 | } |
rgrover1 | 0:0b799af9d58e | 38 | |
rgrover1 | 0:0b799af9d58e | 39 | void SimpleStringBuffer::clear() |
rgrover1 | 0:0b799af9d58e | 40 | { |
rgrover1 | 0:0b799af9d58e | 41 | positions_filled_ = 0; |
rgrover1 | 0:0b799af9d58e | 42 | buffer_[0] = '\0'; |
rgrover1 | 0:0b799af9d58e | 43 | } |
rgrover1 | 0:0b799af9d58e | 44 | |
rgrover1 | 0:0b799af9d58e | 45 | void SimpleStringBuffer::add(const char* format, ...) |
rgrover1 | 0:0b799af9d58e | 46 | { |
rgrover1 | 0:0b799af9d58e | 47 | int count = 0; |
rgrover1 | 0:0b799af9d58e | 48 | size_t positions_left = write_limit_ - positions_filled_; |
rgrover1 | 0:0b799af9d58e | 49 | if (positions_left <= 0) return; |
rgrover1 | 0:0b799af9d58e | 50 | |
rgrover1 | 0:0b799af9d58e | 51 | va_list arguments; |
rgrover1 | 0:0b799af9d58e | 52 | va_start(arguments, format); |
rgrover1 | 0:0b799af9d58e | 53 | count = PlatformSpecificVSNprintf(buffer_ + positions_filled_, positions_left+1, format, arguments); |
rgrover1 | 0:0b799af9d58e | 54 | if (count > 0) positions_filled_ += (size_t) count; |
rgrover1 | 0:0b799af9d58e | 55 | if (positions_filled_ > write_limit_) positions_filled_ = write_limit_; |
rgrover1 | 0:0b799af9d58e | 56 | va_end(arguments); |
rgrover1 | 0:0b799af9d58e | 57 | } |
rgrover1 | 0:0b799af9d58e | 58 | |
rgrover1 | 0:0b799af9d58e | 59 | char* SimpleStringBuffer::toString() |
rgrover1 | 0:0b799af9d58e | 60 | { |
rgrover1 | 0:0b799af9d58e | 61 | return buffer_; |
rgrover1 | 0:0b799af9d58e | 62 | } |
rgrover1 | 0:0b799af9d58e | 63 | |
rgrover1 | 0:0b799af9d58e | 64 | void SimpleStringBuffer::setWriteLimit(size_t write_limit) |
rgrover1 | 0:0b799af9d58e | 65 | { |
rgrover1 | 0:0b799af9d58e | 66 | write_limit_ = write_limit; |
rgrover1 | 0:0b799af9d58e | 67 | if (write_limit_ > SIMPLE_STRING_BUFFER_LEN-1) |
rgrover1 | 0:0b799af9d58e | 68 | write_limit_ = SIMPLE_STRING_BUFFER_LEN-1; |
rgrover1 | 0:0b799af9d58e | 69 | } |
rgrover1 | 0:0b799af9d58e | 70 | void SimpleStringBuffer::resetWriteLimit() |
rgrover1 | 0:0b799af9d58e | 71 | { |
rgrover1 | 0:0b799af9d58e | 72 | write_limit_ = SIMPLE_STRING_BUFFER_LEN-1; |
rgrover1 | 0:0b799af9d58e | 73 | } |
rgrover1 | 0:0b799af9d58e | 74 | |
rgrover1 | 0:0b799af9d58e | 75 | bool SimpleStringBuffer::reachedItsCapacity() |
rgrover1 | 0:0b799af9d58e | 76 | { |
rgrover1 | 0:0b799af9d58e | 77 | return positions_filled_ >= write_limit_; |
rgrover1 | 0:0b799af9d58e | 78 | } |
rgrover1 | 0:0b799af9d58e | 79 | |
rgrover1 | 0:0b799af9d58e | 80 | //////////////////////// |
rgrover1 | 0:0b799af9d58e | 81 | |
rgrover1 | 0:0b799af9d58e | 82 | #define MEM_LEAK_TOO_MUCH "\netc etc etc etc. !!!! Too much memory leaks to report. Bailing out\n" |
rgrover1 | 0:0b799af9d58e | 83 | #define MEM_LEAK_FOOTER "Total number of leaks: " |
rgrover1 | 0:0b799af9d58e | 84 | #define MEM_LEAK_ADDITION_MALLOC_WARNING "NOTE:\n" \ |
rgrover1 | 0:0b799af9d58e | 85 | "\tMemory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc,\n" \ |
rgrover1 | 0:0b799af9d58e | 86 | "\tbut deallocate using the standard free.\n" \ |
rgrover1 | 0:0b799af9d58e | 87 | "\tIf this is the case, check whether your malloc/free replacements are working (#define malloc cpputest_malloc etc).\n" |
rgrover1 | 0:0b799af9d58e | 88 | |
rgrover1 | 0:0b799af9d58e | 89 | MemoryLeakOutputStringBuffer::MemoryLeakOutputStringBuffer() |
rgrover1 | 0:0b799af9d58e | 90 | : total_leaks_(0), giveWarningOnUsingMalloc_(false) |
rgrover1 | 0:0b799af9d58e | 91 | { |
rgrover1 | 0:0b799af9d58e | 92 | } |
rgrover1 | 0:0b799af9d58e | 93 | |
rgrover1 | 0:0b799af9d58e | 94 | void MemoryLeakOutputStringBuffer::addAllocationLocation(const char* allocationFile, int allocationLineNumber, size_t allocationSize, TestMemoryAllocator* allocator) |
rgrover1 | 0:0b799af9d58e | 95 | { |
rgrover1 | 0:0b799af9d58e | 96 | outputBuffer_.add(" allocated at file: %s line: %d size: %lu type: %s\n", allocationFile, allocationLineNumber, (unsigned long) allocationSize, allocator->alloc_name()); |
rgrover1 | 0:0b799af9d58e | 97 | } |
rgrover1 | 0:0b799af9d58e | 98 | |
rgrover1 | 0:0b799af9d58e | 99 | void MemoryLeakOutputStringBuffer::addDeallocationLocation(const char* freeFile, int freeLineNumber, TestMemoryAllocator* allocator) |
rgrover1 | 0:0b799af9d58e | 100 | { |
rgrover1 | 0:0b799af9d58e | 101 | outputBuffer_.add(" deallocated at file: %s line: %d type: %s\n", freeFile, freeLineNumber, allocator->free_name()); |
rgrover1 | 0:0b799af9d58e | 102 | } |
rgrover1 | 0:0b799af9d58e | 103 | |
rgrover1 | 0:0b799af9d58e | 104 | void MemoryLeakOutputStringBuffer::addNoMemoryLeaksMessage() |
rgrover1 | 0:0b799af9d58e | 105 | { |
rgrover1 | 0:0b799af9d58e | 106 | outputBuffer_.add("No memory leaks were detected."); |
rgrover1 | 0:0b799af9d58e | 107 | } |
rgrover1 | 0:0b799af9d58e | 108 | |
rgrover1 | 0:0b799af9d58e | 109 | void MemoryLeakOutputStringBuffer::startMemoryLeakReporting() |
rgrover1 | 0:0b799af9d58e | 110 | { |
rgrover1 | 0:0b799af9d58e | 111 | giveWarningOnUsingMalloc_ = false; |
rgrover1 | 0:0b799af9d58e | 112 | total_leaks_ = 0; |
rgrover1 | 0:0b799af9d58e | 113 | |
rgrover1 | 0:0b799af9d58e | 114 | size_t memory_leak_normal_footer_size = sizeof(MEM_LEAK_FOOTER) + 10 + sizeof(MEM_LEAK_TOO_MUCH); /* the number of leaks */ |
rgrover1 | 0:0b799af9d58e | 115 | size_t memory_leak_foot_size_with_malloc_warning = memory_leak_normal_footer_size + sizeof(MEM_LEAK_ADDITION_MALLOC_WARNING); |
rgrover1 | 0:0b799af9d58e | 116 | |
rgrover1 | 0:0b799af9d58e | 117 | outputBuffer_.setWriteLimit(SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN - memory_leak_foot_size_with_malloc_warning); |
rgrover1 | 0:0b799af9d58e | 118 | } |
rgrover1 | 0:0b799af9d58e | 119 | |
rgrover1 | 0:0b799af9d58e | 120 | void MemoryLeakOutputStringBuffer::reportMemoryLeak(MemoryLeakDetectorNode* leak) |
rgrover1 | 0:0b799af9d58e | 121 | { |
rgrover1 | 0:0b799af9d58e | 122 | if (total_leaks_ == 0) { |
rgrover1 | 0:0b799af9d58e | 123 | addMemoryLeakHeader(); |
rgrover1 | 0:0b799af9d58e | 124 | } |
rgrover1 | 0:0b799af9d58e | 125 | |
rgrover1 | 0:0b799af9d58e | 126 | total_leaks_++; |
rgrover1 | 0:0b799af9d58e | 127 | outputBuffer_.add("Alloc num (%u) Leak size: %lu Allocated at: %s and line: %d. Type: \"%s\"\n\t Memory: <%p> Content: \"%.15s\"\n", |
rgrover1 | 0:0b799af9d58e | 128 | leak->number_, (unsigned long) leak->size_, leak->file_, leak->line_, leak->allocator_->alloc_name(), leak->memory_, leak->memory_); |
rgrover1 | 0:0b799af9d58e | 129 | |
rgrover1 | 0:0b799af9d58e | 130 | if (PlatformSpecificStrCmp(leak->allocator_->alloc_name(), "malloc") == 0) |
rgrover1 | 0:0b799af9d58e | 131 | giveWarningOnUsingMalloc_ = true; |
rgrover1 | 0:0b799af9d58e | 132 | } |
rgrover1 | 0:0b799af9d58e | 133 | |
rgrover1 | 0:0b799af9d58e | 134 | void MemoryLeakOutputStringBuffer::stopMemoryLeakReporting() |
rgrover1 | 0:0b799af9d58e | 135 | { |
rgrover1 | 0:0b799af9d58e | 136 | if (total_leaks_ == 0) { |
rgrover1 | 0:0b799af9d58e | 137 | addNoMemoryLeaksMessage(); |
rgrover1 | 0:0b799af9d58e | 138 | return; |
rgrover1 | 0:0b799af9d58e | 139 | } |
rgrover1 | 0:0b799af9d58e | 140 | |
rgrover1 | 0:0b799af9d58e | 141 | bool buffer_reached_its_capacity = outputBuffer_.reachedItsCapacity(); |
rgrover1 | 0:0b799af9d58e | 142 | outputBuffer_.resetWriteLimit(); |
rgrover1 | 0:0b799af9d58e | 143 | |
rgrover1 | 0:0b799af9d58e | 144 | if (buffer_reached_its_capacity) |
rgrover1 | 0:0b799af9d58e | 145 | addErrorMessageForTooMuchLeaks(); |
rgrover1 | 0:0b799af9d58e | 146 | |
rgrover1 | 0:0b799af9d58e | 147 | addMemoryLeakFooter(total_leaks_); |
rgrover1 | 0:0b799af9d58e | 148 | |
rgrover1 | 0:0b799af9d58e | 149 | if (giveWarningOnUsingMalloc_) |
rgrover1 | 0:0b799af9d58e | 150 | addWarningForUsingMalloc(); |
rgrover1 | 0:0b799af9d58e | 151 | |
rgrover1 | 0:0b799af9d58e | 152 | } |
rgrover1 | 0:0b799af9d58e | 153 | |
rgrover1 | 0:0b799af9d58e | 154 | void MemoryLeakOutputStringBuffer::addMemoryLeakHeader() |
rgrover1 | 0:0b799af9d58e | 155 | { |
rgrover1 | 0:0b799af9d58e | 156 | outputBuffer_.add("Memory leak(s) found.\n"); |
rgrover1 | 0:0b799af9d58e | 157 | } |
rgrover1 | 0:0b799af9d58e | 158 | |
rgrover1 | 0:0b799af9d58e | 159 | void MemoryLeakOutputStringBuffer::addErrorMessageForTooMuchLeaks() |
rgrover1 | 0:0b799af9d58e | 160 | { |
rgrover1 | 0:0b799af9d58e | 161 | outputBuffer_.add(MEM_LEAK_TOO_MUCH); |
rgrover1 | 0:0b799af9d58e | 162 | } |
rgrover1 | 0:0b799af9d58e | 163 | |
rgrover1 | 0:0b799af9d58e | 164 | void MemoryLeakOutputStringBuffer::addMemoryLeakFooter(int amountOfLeaks) |
rgrover1 | 0:0b799af9d58e | 165 | { |
rgrover1 | 0:0b799af9d58e | 166 | outputBuffer_.add("%s %d\n", MEM_LEAK_FOOTER, amountOfLeaks); |
rgrover1 | 0:0b799af9d58e | 167 | } |
rgrover1 | 0:0b799af9d58e | 168 | |
rgrover1 | 0:0b799af9d58e | 169 | void MemoryLeakOutputStringBuffer::addWarningForUsingMalloc() |
rgrover1 | 0:0b799af9d58e | 170 | { |
rgrover1 | 0:0b799af9d58e | 171 | outputBuffer_.add(MEM_LEAK_ADDITION_MALLOC_WARNING); |
rgrover1 | 0:0b799af9d58e | 172 | } |
rgrover1 | 0:0b799af9d58e | 173 | |
rgrover1 | 0:0b799af9d58e | 174 | void MemoryLeakOutputStringBuffer::reportDeallocateNonAllocatedMemoryFailure(const char* freeFile, int freeLine, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) |
rgrover1 | 0:0b799af9d58e | 175 | { |
rgrover1 | 0:0b799af9d58e | 176 | reportFailure("Deallocating non-allocated memory\n", "<unknown>", 0, 0, NullUnknownAllocator::defaultAllocator(), freeFile, freeLine, freeAllocator, reporter); |
rgrover1 | 0:0b799af9d58e | 177 | } |
rgrover1 | 0:0b799af9d58e | 178 | |
rgrover1 | 0:0b799af9d58e | 179 | void MemoryLeakOutputStringBuffer::reportAllocationDeallocationMismatchFailure(MemoryLeakDetectorNode* node, const char* freeFile, int freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) |
rgrover1 | 0:0b799af9d58e | 180 | { |
rgrover1 | 0:0b799af9d58e | 181 | reportFailure("Allocation/deallocation type mismatch\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter); |
rgrover1 | 0:0b799af9d58e | 182 | } |
rgrover1 | 0:0b799af9d58e | 183 | |
rgrover1 | 0:0b799af9d58e | 184 | void MemoryLeakOutputStringBuffer::reportMemoryCorruptionFailure(MemoryLeakDetectorNode* node, const char* freeFile, int freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) |
rgrover1 | 0:0b799af9d58e | 185 | { |
rgrover1 | 0:0b799af9d58e | 186 | reportFailure("Memory corruption (written out of bounds?)\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter); |
rgrover1 | 0:0b799af9d58e | 187 | } |
rgrover1 | 0:0b799af9d58e | 188 | |
rgrover1 | 0:0b799af9d58e | 189 | void MemoryLeakOutputStringBuffer::reportFailure(const char* message, const char* allocFile, int allocLine, size_t allocSize, TestMemoryAllocator* allocAllocator, const char* freeFile, int freeLine, |
rgrover1 | 0:0b799af9d58e | 190 | TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter) |
rgrover1 | 0:0b799af9d58e | 191 | { |
rgrover1 | 0:0b799af9d58e | 192 | outputBuffer_.add("%s", message); |
rgrover1 | 0:0b799af9d58e | 193 | addAllocationLocation(allocFile, allocLine, allocSize, allocAllocator); |
rgrover1 | 0:0b799af9d58e | 194 | addDeallocationLocation(freeFile, freeLine, freeAllocator); |
rgrover1 | 0:0b799af9d58e | 195 | reporter->fail(toString()); |
rgrover1 | 0:0b799af9d58e | 196 | } |
rgrover1 | 0:0b799af9d58e | 197 | |
rgrover1 | 0:0b799af9d58e | 198 | |
rgrover1 | 0:0b799af9d58e | 199 | char* MemoryLeakOutputStringBuffer::toString() |
rgrover1 | 0:0b799af9d58e | 200 | { |
rgrover1 | 0:0b799af9d58e | 201 | return outputBuffer_.toString(); |
rgrover1 | 0:0b799af9d58e | 202 | } |
rgrover1 | 0:0b799af9d58e | 203 | |
rgrover1 | 0:0b799af9d58e | 204 | void MemoryLeakOutputStringBuffer::clear() |
rgrover1 | 0:0b799af9d58e | 205 | { |
rgrover1 | 0:0b799af9d58e | 206 | outputBuffer_.clear(); |
rgrover1 | 0:0b799af9d58e | 207 | } |
rgrover1 | 0:0b799af9d58e | 208 | |
rgrover1 | 0:0b799af9d58e | 209 | //////////////////////// |
rgrover1 | 0:0b799af9d58e | 210 | |
rgrover1 | 0:0b799af9d58e | 211 | void MemoryLeakDetectorNode::init(char* memory, unsigned number, size_t size, TestMemoryAllocator* allocator, MemLeakPeriod period, const char* file, int line) |
rgrover1 | 0:0b799af9d58e | 212 | { |
rgrover1 | 0:0b799af9d58e | 213 | number_ = number; |
rgrover1 | 0:0b799af9d58e | 214 | memory_ = memory; |
rgrover1 | 0:0b799af9d58e | 215 | size_ = size; |
rgrover1 | 0:0b799af9d58e | 216 | allocator_ = allocator; |
rgrover1 | 0:0b799af9d58e | 217 | period_ = period; |
rgrover1 | 0:0b799af9d58e | 218 | file_ = file; |
rgrover1 | 0:0b799af9d58e | 219 | line_ = line; |
rgrover1 | 0:0b799af9d58e | 220 | } |
rgrover1 | 0:0b799af9d58e | 221 | |
rgrover1 | 0:0b799af9d58e | 222 | /////////////////////// |
rgrover1 | 0:0b799af9d58e | 223 | |
rgrover1 | 0:0b799af9d58e | 224 | bool MemoryLeakDetectorList::isInPeriod(MemoryLeakDetectorNode* node, MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 225 | { |
rgrover1 | 0:0b799af9d58e | 226 | return period == mem_leak_period_all || node->period_ == period || (node->period_ != mem_leak_period_disabled && period == mem_leak_period_enabled); |
rgrover1 | 0:0b799af9d58e | 227 | } |
rgrover1 | 0:0b799af9d58e | 228 | |
rgrover1 | 0:0b799af9d58e | 229 | void MemoryLeakDetectorList::clearAllAccounting(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 230 | { |
rgrover1 | 0:0b799af9d58e | 231 | MemoryLeakDetectorNode* cur = head_; |
rgrover1 | 0:0b799af9d58e | 232 | MemoryLeakDetectorNode* prev = 0; |
rgrover1 | 0:0b799af9d58e | 233 | |
rgrover1 | 0:0b799af9d58e | 234 | while (cur) { |
rgrover1 | 0:0b799af9d58e | 235 | if (isInPeriod(cur, period)) { |
rgrover1 | 0:0b799af9d58e | 236 | if (prev) { |
rgrover1 | 0:0b799af9d58e | 237 | prev->next_ = cur->next_; |
rgrover1 | 0:0b799af9d58e | 238 | cur = prev; |
rgrover1 | 0:0b799af9d58e | 239 | } |
rgrover1 | 0:0b799af9d58e | 240 | else { |
rgrover1 | 0:0b799af9d58e | 241 | head_ = cur->next_; |
rgrover1 | 0:0b799af9d58e | 242 | cur = head_; |
rgrover1 | 0:0b799af9d58e | 243 | continue; |
rgrover1 | 0:0b799af9d58e | 244 | } |
rgrover1 | 0:0b799af9d58e | 245 | } |
rgrover1 | 0:0b799af9d58e | 246 | prev = cur; |
rgrover1 | 0:0b799af9d58e | 247 | cur = cur->next_; |
rgrover1 | 0:0b799af9d58e | 248 | } |
rgrover1 | 0:0b799af9d58e | 249 | } |
rgrover1 | 0:0b799af9d58e | 250 | |
rgrover1 | 0:0b799af9d58e | 251 | void MemoryLeakDetectorList::addNewNode(MemoryLeakDetectorNode* node) |
rgrover1 | 0:0b799af9d58e | 252 | { |
rgrover1 | 0:0b799af9d58e | 253 | node->next_ = head_; |
rgrover1 | 0:0b799af9d58e | 254 | head_ = node; |
rgrover1 | 0:0b799af9d58e | 255 | } |
rgrover1 | 0:0b799af9d58e | 256 | |
rgrover1 | 0:0b799af9d58e | 257 | MemoryLeakDetectorNode* MemoryLeakDetectorList::removeNode(char* memory) |
rgrover1 | 0:0b799af9d58e | 258 | { |
rgrover1 | 0:0b799af9d58e | 259 | MemoryLeakDetectorNode* cur = head_; |
rgrover1 | 0:0b799af9d58e | 260 | MemoryLeakDetectorNode* prev = 0; |
rgrover1 | 0:0b799af9d58e | 261 | while (cur) { |
rgrover1 | 0:0b799af9d58e | 262 | if (cur->memory_ == memory) { |
rgrover1 | 0:0b799af9d58e | 263 | if (prev) { |
rgrover1 | 0:0b799af9d58e | 264 | prev->next_ = cur->next_; |
rgrover1 | 0:0b799af9d58e | 265 | return cur; |
rgrover1 | 0:0b799af9d58e | 266 | } |
rgrover1 | 0:0b799af9d58e | 267 | else { |
rgrover1 | 0:0b799af9d58e | 268 | head_ = cur->next_; |
rgrover1 | 0:0b799af9d58e | 269 | return cur; |
rgrover1 | 0:0b799af9d58e | 270 | } |
rgrover1 | 0:0b799af9d58e | 271 | } |
rgrover1 | 0:0b799af9d58e | 272 | prev = cur; |
rgrover1 | 0:0b799af9d58e | 273 | cur = cur->next_; |
rgrover1 | 0:0b799af9d58e | 274 | } |
rgrover1 | 0:0b799af9d58e | 275 | return 0; |
rgrover1 | 0:0b799af9d58e | 276 | } |
rgrover1 | 0:0b799af9d58e | 277 | |
rgrover1 | 0:0b799af9d58e | 278 | MemoryLeakDetectorNode* MemoryLeakDetectorList::retrieveNode(char* memory) |
rgrover1 | 0:0b799af9d58e | 279 | { |
rgrover1 | 0:0b799af9d58e | 280 | MemoryLeakDetectorNode* cur = head_; |
rgrover1 | 0:0b799af9d58e | 281 | while (cur) { |
rgrover1 | 0:0b799af9d58e | 282 | if (cur->memory_ == memory) |
rgrover1 | 0:0b799af9d58e | 283 | return cur; |
rgrover1 | 0:0b799af9d58e | 284 | cur = cur->next_; |
rgrover1 | 0:0b799af9d58e | 285 | } |
rgrover1 | 0:0b799af9d58e | 286 | return NULL; |
rgrover1 | 0:0b799af9d58e | 287 | } |
rgrover1 | 0:0b799af9d58e | 288 | |
rgrover1 | 0:0b799af9d58e | 289 | MemoryLeakDetectorNode* MemoryLeakDetectorList::getLeakFrom(MemoryLeakDetectorNode* node, MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 290 | { |
rgrover1 | 0:0b799af9d58e | 291 | for (MemoryLeakDetectorNode* cur = node; cur; cur = cur->next_) |
rgrover1 | 0:0b799af9d58e | 292 | if (isInPeriod(cur, period)) return cur; |
rgrover1 | 0:0b799af9d58e | 293 | return 0; |
rgrover1 | 0:0b799af9d58e | 294 | } |
rgrover1 | 0:0b799af9d58e | 295 | |
rgrover1 | 0:0b799af9d58e | 296 | MemoryLeakDetectorNode* MemoryLeakDetectorList::getFirstLeak(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 297 | { |
rgrover1 | 0:0b799af9d58e | 298 | return getLeakFrom(head_, period); |
rgrover1 | 0:0b799af9d58e | 299 | } |
rgrover1 | 0:0b799af9d58e | 300 | |
rgrover1 | 0:0b799af9d58e | 301 | MemoryLeakDetectorNode* MemoryLeakDetectorList::getNextLeak(MemoryLeakDetectorNode* node, MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 302 | { |
rgrover1 | 0:0b799af9d58e | 303 | return getLeakFrom(node->next_, period); |
rgrover1 | 0:0b799af9d58e | 304 | } |
rgrover1 | 0:0b799af9d58e | 305 | |
rgrover1 | 0:0b799af9d58e | 306 | int MemoryLeakDetectorList::getTotalLeaks(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 307 | { |
rgrover1 | 0:0b799af9d58e | 308 | int total_leaks = 0; |
rgrover1 | 0:0b799af9d58e | 309 | for (MemoryLeakDetectorNode* node = head_; node; node = node->next_) { |
rgrover1 | 0:0b799af9d58e | 310 | if (isInPeriod(node, period)) total_leaks++; |
rgrover1 | 0:0b799af9d58e | 311 | } |
rgrover1 | 0:0b799af9d58e | 312 | return total_leaks; |
rgrover1 | 0:0b799af9d58e | 313 | } |
rgrover1 | 0:0b799af9d58e | 314 | |
rgrover1 | 0:0b799af9d58e | 315 | bool MemoryLeakDetectorList::hasLeaks(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 316 | { |
rgrover1 | 0:0b799af9d58e | 317 | for (MemoryLeakDetectorNode* node = head_; node; node = node->next_) |
rgrover1 | 0:0b799af9d58e | 318 | if (isInPeriod(node, period)) return true; |
rgrover1 | 0:0b799af9d58e | 319 | return false; |
rgrover1 | 0:0b799af9d58e | 320 | } |
rgrover1 | 0:0b799af9d58e | 321 | |
rgrover1 | 0:0b799af9d58e | 322 | ///////////////////////////////////////////////////////////// |
rgrover1 | 0:0b799af9d58e | 323 | |
rgrover1 | 0:0b799af9d58e | 324 | unsigned long MemoryLeakDetectorTable::hash(char* memory) |
rgrover1 | 0:0b799af9d58e | 325 | { |
rgrover1 | 0:0b799af9d58e | 326 | return (unsigned long)((size_t)memory % hash_prime); |
rgrover1 | 0:0b799af9d58e | 327 | } |
rgrover1 | 0:0b799af9d58e | 328 | |
rgrover1 | 0:0b799af9d58e | 329 | void MemoryLeakDetectorTable::clearAllAccounting(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 330 | { |
rgrover1 | 0:0b799af9d58e | 331 | for (int i = 0; i < hash_prime; i++) |
rgrover1 | 0:0b799af9d58e | 332 | table_[i].clearAllAccounting(period); |
rgrover1 | 0:0b799af9d58e | 333 | } |
rgrover1 | 0:0b799af9d58e | 334 | |
rgrover1 | 0:0b799af9d58e | 335 | void MemoryLeakDetectorTable::addNewNode(MemoryLeakDetectorNode* node) |
rgrover1 | 0:0b799af9d58e | 336 | { |
rgrover1 | 0:0b799af9d58e | 337 | table_[hash(node->memory_)].addNewNode(node); |
rgrover1 | 0:0b799af9d58e | 338 | } |
rgrover1 | 0:0b799af9d58e | 339 | |
rgrover1 | 0:0b799af9d58e | 340 | MemoryLeakDetectorNode* MemoryLeakDetectorTable::removeNode(char* memory) |
rgrover1 | 0:0b799af9d58e | 341 | { |
rgrover1 | 0:0b799af9d58e | 342 | return table_[hash(memory)].removeNode(memory); |
rgrover1 | 0:0b799af9d58e | 343 | } |
rgrover1 | 0:0b799af9d58e | 344 | |
rgrover1 | 0:0b799af9d58e | 345 | MemoryLeakDetectorNode* MemoryLeakDetectorTable::retrieveNode(char* memory) |
rgrover1 | 0:0b799af9d58e | 346 | { |
rgrover1 | 0:0b799af9d58e | 347 | return table_[hash(memory)].retrieveNode(memory); |
rgrover1 | 0:0b799af9d58e | 348 | } |
rgrover1 | 0:0b799af9d58e | 349 | |
rgrover1 | 0:0b799af9d58e | 350 | bool MemoryLeakDetectorTable::hasLeaks(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 351 | { |
rgrover1 | 0:0b799af9d58e | 352 | for (int i = 0; i < hash_prime; i++) |
rgrover1 | 0:0b799af9d58e | 353 | if (table_[i].hasLeaks(period)) return true; |
rgrover1 | 0:0b799af9d58e | 354 | return false; |
rgrover1 | 0:0b799af9d58e | 355 | } |
rgrover1 | 0:0b799af9d58e | 356 | |
rgrover1 | 0:0b799af9d58e | 357 | int MemoryLeakDetectorTable::getTotalLeaks(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 358 | { |
rgrover1 | 0:0b799af9d58e | 359 | int total_leaks = 0; |
rgrover1 | 0:0b799af9d58e | 360 | for (int i = 0; i < hash_prime; i++) |
rgrover1 | 0:0b799af9d58e | 361 | total_leaks += table_[i].getTotalLeaks(period); |
rgrover1 | 0:0b799af9d58e | 362 | return total_leaks; |
rgrover1 | 0:0b799af9d58e | 363 | } |
rgrover1 | 0:0b799af9d58e | 364 | |
rgrover1 | 0:0b799af9d58e | 365 | MemoryLeakDetectorNode* MemoryLeakDetectorTable::getFirstLeak(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 366 | { |
rgrover1 | 0:0b799af9d58e | 367 | for (int i = 0; i < hash_prime; i++) { |
rgrover1 | 0:0b799af9d58e | 368 | MemoryLeakDetectorNode* node = table_[i].getFirstLeak(period); |
rgrover1 | 0:0b799af9d58e | 369 | if (node) return node; |
rgrover1 | 0:0b799af9d58e | 370 | } |
rgrover1 | 0:0b799af9d58e | 371 | return 0; |
rgrover1 | 0:0b799af9d58e | 372 | } |
rgrover1 | 0:0b799af9d58e | 373 | |
rgrover1 | 0:0b799af9d58e | 374 | MemoryLeakDetectorNode* MemoryLeakDetectorTable::getNextLeak(MemoryLeakDetectorNode* leak, MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 375 | { |
rgrover1 | 0:0b799af9d58e | 376 | unsigned long i = hash(leak->memory_); |
rgrover1 | 0:0b799af9d58e | 377 | MemoryLeakDetectorNode* node = table_[i].getNextLeak(leak, period); |
rgrover1 | 0:0b799af9d58e | 378 | if (node) return node; |
rgrover1 | 0:0b799af9d58e | 379 | |
rgrover1 | 0:0b799af9d58e | 380 | for (++i; i < hash_prime; i++) { |
rgrover1 | 0:0b799af9d58e | 381 | node = table_[i].getFirstLeak(period); |
rgrover1 | 0:0b799af9d58e | 382 | if (node) return node; |
rgrover1 | 0:0b799af9d58e | 383 | } |
rgrover1 | 0:0b799af9d58e | 384 | return 0; |
rgrover1 | 0:0b799af9d58e | 385 | } |
rgrover1 | 0:0b799af9d58e | 386 | |
rgrover1 | 0:0b799af9d58e | 387 | ///////////////////////////////////////////////////////////// |
rgrover1 | 0:0b799af9d58e | 388 | |
rgrover1 | 0:0b799af9d58e | 389 | MemoryLeakDetector::MemoryLeakDetector(MemoryLeakFailure* reporter) |
rgrover1 | 0:0b799af9d58e | 390 | { |
rgrover1 | 0:0b799af9d58e | 391 | doAllocationTypeChecking_ = true; |
rgrover1 | 0:0b799af9d58e | 392 | allocationSequenceNumber_ = 1; |
rgrover1 | 0:0b799af9d58e | 393 | current_period_ = mem_leak_period_disabled; |
rgrover1 | 0:0b799af9d58e | 394 | reporter_ = reporter; |
rgrover1 | 0:0b799af9d58e | 395 | outputBuffer_ = MemoryLeakOutputStringBuffer(); |
rgrover1 | 0:0b799af9d58e | 396 | memoryTable_ = MemoryLeakDetectorTable(); |
rgrover1 | 0:0b799af9d58e | 397 | } |
rgrover1 | 0:0b799af9d58e | 398 | |
rgrover1 | 0:0b799af9d58e | 399 | void MemoryLeakDetector::clearAllAccounting(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 400 | { |
rgrover1 | 0:0b799af9d58e | 401 | memoryTable_.clearAllAccounting(period); |
rgrover1 | 0:0b799af9d58e | 402 | } |
rgrover1 | 0:0b799af9d58e | 403 | |
rgrover1 | 0:0b799af9d58e | 404 | void MemoryLeakDetector::startChecking() |
rgrover1 | 0:0b799af9d58e | 405 | { |
rgrover1 | 0:0b799af9d58e | 406 | outputBuffer_.clear(); |
rgrover1 | 0:0b799af9d58e | 407 | current_period_ = mem_leak_period_checking; |
rgrover1 | 0:0b799af9d58e | 408 | } |
rgrover1 | 0:0b799af9d58e | 409 | |
rgrover1 | 0:0b799af9d58e | 410 | void MemoryLeakDetector::stopChecking() |
rgrover1 | 0:0b799af9d58e | 411 | { |
rgrover1 | 0:0b799af9d58e | 412 | current_period_ = mem_leak_period_enabled; |
rgrover1 | 0:0b799af9d58e | 413 | } |
rgrover1 | 0:0b799af9d58e | 414 | |
rgrover1 | 0:0b799af9d58e | 415 | void MemoryLeakDetector::enable() |
rgrover1 | 0:0b799af9d58e | 416 | { |
rgrover1 | 0:0b799af9d58e | 417 | current_period_ = mem_leak_period_enabled; |
rgrover1 | 0:0b799af9d58e | 418 | } |
rgrover1 | 0:0b799af9d58e | 419 | |
rgrover1 | 0:0b799af9d58e | 420 | void MemoryLeakDetector::disable() |
rgrover1 | 0:0b799af9d58e | 421 | { |
rgrover1 | 0:0b799af9d58e | 422 | current_period_ = mem_leak_period_disabled; |
rgrover1 | 0:0b799af9d58e | 423 | } |
rgrover1 | 0:0b799af9d58e | 424 | |
rgrover1 | 0:0b799af9d58e | 425 | void MemoryLeakDetector::disableAllocationTypeChecking() |
rgrover1 | 0:0b799af9d58e | 426 | { |
rgrover1 | 0:0b799af9d58e | 427 | doAllocationTypeChecking_ = false; |
rgrover1 | 0:0b799af9d58e | 428 | } |
rgrover1 | 0:0b799af9d58e | 429 | |
rgrover1 | 0:0b799af9d58e | 430 | void MemoryLeakDetector::enableAllocationTypeChecking() |
rgrover1 | 0:0b799af9d58e | 431 | { |
rgrover1 | 0:0b799af9d58e | 432 | doAllocationTypeChecking_ = true; |
rgrover1 | 0:0b799af9d58e | 433 | } |
rgrover1 | 0:0b799af9d58e | 434 | |
rgrover1 | 0:0b799af9d58e | 435 | unsigned MemoryLeakDetector::getCurrentAllocationNumber() |
rgrover1 | 0:0b799af9d58e | 436 | { |
rgrover1 | 0:0b799af9d58e | 437 | return allocationSequenceNumber_; |
rgrover1 | 0:0b799af9d58e | 438 | } |
rgrover1 | 0:0b799af9d58e | 439 | |
rgrover1 | 0:0b799af9d58e | 440 | static size_t calculateVoidPointerAlignedSize(size_t size) |
rgrover1 | 0:0b799af9d58e | 441 | { |
rgrover1 | 0:0b799af9d58e | 442 | return (sizeof(void*) - (size % sizeof(void*))) + size; |
rgrover1 | 0:0b799af9d58e | 443 | } |
rgrover1 | 0:0b799af9d58e | 444 | |
rgrover1 | 0:0b799af9d58e | 445 | size_t MemoryLeakDetector::sizeOfMemoryWithCorruptionInfo(size_t size) |
rgrover1 | 0:0b799af9d58e | 446 | { |
rgrover1 | 0:0b799af9d58e | 447 | return calculateVoidPointerAlignedSize(size + memory_corruption_buffer_size); |
rgrover1 | 0:0b799af9d58e | 448 | } |
rgrover1 | 0:0b799af9d58e | 449 | |
rgrover1 | 0:0b799af9d58e | 450 | MemoryLeakDetectorNode* MemoryLeakDetector::getNodeFromMemoryPointer(char* memory, size_t memory_size) |
rgrover1 | 0:0b799af9d58e | 451 | { |
rgrover1 | 0:0b799af9d58e | 452 | return (MemoryLeakDetectorNode*) (void*) (memory + sizeOfMemoryWithCorruptionInfo(memory_size)); |
rgrover1 | 0:0b799af9d58e | 453 | } |
rgrover1 | 0:0b799af9d58e | 454 | |
rgrover1 | 0:0b799af9d58e | 455 | void MemoryLeakDetector::storeLeakInformation(MemoryLeakDetectorNode * node, char *new_memory, size_t size, TestMemoryAllocator *allocator, const char *file, int line) |
rgrover1 | 0:0b799af9d58e | 456 | { |
rgrover1 | 0:0b799af9d58e | 457 | node->init(new_memory, allocationSequenceNumber_++, size, allocator, current_period_, file, line); |
rgrover1 | 0:0b799af9d58e | 458 | addMemoryCorruptionInformation(node->memory_ + node->size_); |
rgrover1 | 0:0b799af9d58e | 459 | memoryTable_.addNewNode(node); |
rgrover1 | 0:0b799af9d58e | 460 | } |
rgrover1 | 0:0b799af9d58e | 461 | |
rgrover1 | 0:0b799af9d58e | 462 | char* MemoryLeakDetector::reallocateMemoryAndLeakInformation(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 463 | { |
rgrover1 | 0:0b799af9d58e | 464 | char* new_memory = reallocateMemoryWithAccountingInformation(allocator, memory, size, file, line, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 465 | if (new_memory == NULL) return NULL; |
rgrover1 | 0:0b799af9d58e | 466 | |
rgrover1 | 0:0b799af9d58e | 467 | MemoryLeakDetectorNode *node = createMemoryLeakAccountingInformation(allocator, size, new_memory, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 468 | storeLeakInformation(node, new_memory, size, allocator, file, line); |
rgrover1 | 0:0b799af9d58e | 469 | return node->memory_; |
rgrover1 | 0:0b799af9d58e | 470 | } |
rgrover1 | 0:0b799af9d58e | 471 | |
rgrover1 | 0:0b799af9d58e | 472 | void MemoryLeakDetector::invalidateMemory(char* memory) |
rgrover1 | 0:0b799af9d58e | 473 | { |
rgrover1 | 0:0b799af9d58e | 474 | MemoryLeakDetectorNode* node = memoryTable_.retrieveNode(memory); |
rgrover1 | 0:0b799af9d58e | 475 | if (node) |
rgrover1 | 0:0b799af9d58e | 476 | PlatformSpecificMemset(memory, 0xCD, node->size_); |
rgrover1 | 0:0b799af9d58e | 477 | } |
rgrover1 | 0:0b799af9d58e | 478 | |
rgrover1 | 0:0b799af9d58e | 479 | void MemoryLeakDetector::addMemoryCorruptionInformation(char* memory) |
rgrover1 | 0:0b799af9d58e | 480 | { |
rgrover1 | 0:0b799af9d58e | 481 | memory[0] = 'B'; |
rgrover1 | 0:0b799af9d58e | 482 | memory[1] = 'A'; |
rgrover1 | 0:0b799af9d58e | 483 | memory[2] = 'S'; |
rgrover1 | 0:0b799af9d58e | 484 | } |
rgrover1 | 0:0b799af9d58e | 485 | |
rgrover1 | 0:0b799af9d58e | 486 | bool MemoryLeakDetector::validMemoryCorruptionInformation(char* memory) |
rgrover1 | 0:0b799af9d58e | 487 | { |
rgrover1 | 0:0b799af9d58e | 488 | return memory[0] == 'B' && memory[1] == 'A' && memory[2] == 'S'; |
rgrover1 | 0:0b799af9d58e | 489 | } |
rgrover1 | 0:0b799af9d58e | 490 | |
rgrover1 | 0:0b799af9d58e | 491 | bool MemoryLeakDetector::matchingAllocation(TestMemoryAllocator *alloc_allocator, TestMemoryAllocator *free_allocator) |
rgrover1 | 0:0b799af9d58e | 492 | { |
rgrover1 | 0:0b799af9d58e | 493 | if (alloc_allocator == free_allocator) return true; |
rgrover1 | 0:0b799af9d58e | 494 | if (!doAllocationTypeChecking_) return true; |
rgrover1 | 0:0b799af9d58e | 495 | return free_allocator->isOfEqualType(alloc_allocator); |
rgrover1 | 0:0b799af9d58e | 496 | } |
rgrover1 | 0:0b799af9d58e | 497 | |
rgrover1 | 0:0b799af9d58e | 498 | void MemoryLeakDetector::checkForCorruption(MemoryLeakDetectorNode* node, const char* file, int line, TestMemoryAllocator* allocator, bool allocateNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 499 | { |
rgrover1 | 0:0b799af9d58e | 500 | if (!matchingAllocation(node->allocator_, allocator)) |
rgrover1 | 0:0b799af9d58e | 501 | outputBuffer_.reportAllocationDeallocationMismatchFailure(node, file, line, allocator, reporter_); |
rgrover1 | 0:0b799af9d58e | 502 | else if (!validMemoryCorruptionInformation(node->memory_ + node->size_)) |
rgrover1 | 0:0b799af9d58e | 503 | outputBuffer_.reportMemoryCorruptionFailure(node, file, line, allocator, reporter_); |
rgrover1 | 0:0b799af9d58e | 504 | else if (allocateNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 505 | allocator->freeMemoryLeakNode((char*) node); |
rgrover1 | 0:0b799af9d58e | 506 | } |
rgrover1 | 0:0b799af9d58e | 507 | |
rgrover1 | 0:0b799af9d58e | 508 | char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 509 | { |
rgrover1 | 0:0b799af9d58e | 510 | return allocMemory(allocator, size, UNKNOWN, 0, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 511 | } |
rgrover1 | 0:0b799af9d58e | 512 | |
rgrover1 | 0:0b799af9d58e | 513 | char* MemoryLeakDetector::allocateMemoryWithAccountingInformation(TestMemoryAllocator* allocator, size_t size, const char* file, int line, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 514 | { |
rgrover1 | 0:0b799af9d58e | 515 | if (allocatNodesSeperately) return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size), file, line); |
rgrover1 | 0:0b799af9d58e | 516 | else return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode), file, line); |
rgrover1 | 0:0b799af9d58e | 517 | } |
rgrover1 | 0:0b799af9d58e | 518 | |
rgrover1 | 0:0b799af9d58e | 519 | char* MemoryLeakDetector::reallocateMemoryWithAccountingInformation(TestMemoryAllocator* /*allocator*/, char* memory, size_t size, const char* /*file*/, int /*line*/, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 520 | { |
rgrover1 | 0:0b799af9d58e | 521 | if (allocatNodesSeperately) return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size)); |
rgrover1 | 0:0b799af9d58e | 522 | else return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode)); |
rgrover1 | 0:0b799af9d58e | 523 | } |
rgrover1 | 0:0b799af9d58e | 524 | |
rgrover1 | 0:0b799af9d58e | 525 | MemoryLeakDetectorNode* MemoryLeakDetector::createMemoryLeakAccountingInformation(TestMemoryAllocator* allocator, size_t size, char* memory, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 526 | { |
rgrover1 | 0:0b799af9d58e | 527 | if (allocatNodesSeperately) return (MemoryLeakDetectorNode*) (void*) allocator->allocMemoryLeakNode(sizeof(MemoryLeakDetectorNode)); |
rgrover1 | 0:0b799af9d58e | 528 | else return getNodeFromMemoryPointer(memory, size); |
rgrover1 | 0:0b799af9d58e | 529 | } |
rgrover1 | 0:0b799af9d58e | 530 | |
rgrover1 | 0:0b799af9d58e | 531 | char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, const char* file, int line, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 532 | { |
rgrover1 | 0:0b799af9d58e | 533 | /* With malloc, it is harder to guarantee that the allocator free is called. |
rgrover1 | 0:0b799af9d58e | 534 | * This is because operator new is overloaded via linker symbols, but malloc just via #defines. |
rgrover1 | 0:0b799af9d58e | 535 | * If the same allocation is used and the wrong free is called, it will deallocate the memory leak information |
rgrover1 | 0:0b799af9d58e | 536 | * without the memory leak detector ever noticing it! |
rgrover1 | 0:0b799af9d58e | 537 | * So, for malloc, we'll allocate the memory separately so we can detect this and give a proper error. |
rgrover1 | 0:0b799af9d58e | 538 | */ |
rgrover1 | 0:0b799af9d58e | 539 | |
rgrover1 | 0:0b799af9d58e | 540 | char* memory = allocateMemoryWithAccountingInformation(allocator, size, file, line, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 541 | if (memory == NULL) return NULL; |
rgrover1 | 0:0b799af9d58e | 542 | MemoryLeakDetectorNode* node = createMemoryLeakAccountingInformation(allocator, size, memory, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 543 | |
rgrover1 | 0:0b799af9d58e | 544 | storeLeakInformation(node, memory, size, allocator, file, line); |
rgrover1 | 0:0b799af9d58e | 545 | return node->memory_; |
rgrover1 | 0:0b799af9d58e | 546 | } |
rgrover1 | 0:0b799af9d58e | 547 | |
rgrover1 | 0:0b799af9d58e | 548 | void MemoryLeakDetector::removeMemoryLeakInformationWithoutCheckingOrDeallocatingTheMemoryButDeallocatingTheAccountInformation(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 549 | { |
rgrover1 | 0:0b799af9d58e | 550 | MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory); |
rgrover1 | 0:0b799af9d58e | 551 | if (allocatNodesSeperately) allocator->freeMemoryLeakNode( (char*) node); |
rgrover1 | 0:0b799af9d58e | 552 | } |
rgrover1 | 0:0b799af9d58e | 553 | |
rgrover1 | 0:0b799af9d58e | 554 | void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, const char* file, int line, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 555 | { |
rgrover1 | 0:0b799af9d58e | 556 | if (memory == 0) return; |
rgrover1 | 0:0b799af9d58e | 557 | |
rgrover1 | 0:0b799af9d58e | 558 | MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory); |
rgrover1 | 0:0b799af9d58e | 559 | if (node == NULL) { |
rgrover1 | 0:0b799af9d58e | 560 | outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_); |
rgrover1 | 0:0b799af9d58e | 561 | return; |
rgrover1 | 0:0b799af9d58e | 562 | } |
rgrover1 | 0:0b799af9d58e | 563 | if (!allocator->hasBeenDestroyed()) { |
rgrover1 | 0:0b799af9d58e | 564 | checkForCorruption(node, file, line, allocator, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 565 | allocator->free_memory((char*) memory, file, line); |
rgrover1 | 0:0b799af9d58e | 566 | } |
rgrover1 | 0:0b799af9d58e | 567 | } |
rgrover1 | 0:0b799af9d58e | 568 | |
rgrover1 | 0:0b799af9d58e | 569 | void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 570 | { |
rgrover1 | 0:0b799af9d58e | 571 | deallocMemory(allocator, (char*) memory, UNKNOWN, 0, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 572 | } |
rgrover1 | 0:0b799af9d58e | 573 | |
rgrover1 | 0:0b799af9d58e | 574 | char* MemoryLeakDetector::reallocMemory(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, int line, bool allocatNodesSeperately) |
rgrover1 | 0:0b799af9d58e | 575 | { |
rgrover1 | 0:0b799af9d58e | 576 | if (memory) { |
rgrover1 | 0:0b799af9d58e | 577 | MemoryLeakDetectorNode* node = memoryTable_.removeNode(memory); |
rgrover1 | 0:0b799af9d58e | 578 | if (node == NULL) { |
rgrover1 | 0:0b799af9d58e | 579 | outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_); |
rgrover1 | 0:0b799af9d58e | 580 | return NULL; |
rgrover1 | 0:0b799af9d58e | 581 | } |
rgrover1 | 0:0b799af9d58e | 582 | checkForCorruption(node, file, line, allocator, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 583 | } |
rgrover1 | 0:0b799af9d58e | 584 | return reallocateMemoryAndLeakInformation(allocator, memory, size, file, line, allocatNodesSeperately); |
rgrover1 | 0:0b799af9d58e | 585 | } |
rgrover1 | 0:0b799af9d58e | 586 | |
rgrover1 | 0:0b799af9d58e | 587 | void MemoryLeakDetector::ConstructMemoryLeakReport(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 588 | { |
rgrover1 | 0:0b799af9d58e | 589 | MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(period); |
rgrover1 | 0:0b799af9d58e | 590 | |
rgrover1 | 0:0b799af9d58e | 591 | outputBuffer_.startMemoryLeakReporting(); |
rgrover1 | 0:0b799af9d58e | 592 | |
rgrover1 | 0:0b799af9d58e | 593 | while (leak) { |
rgrover1 | 0:0b799af9d58e | 594 | outputBuffer_.reportMemoryLeak(leak); |
rgrover1 | 0:0b799af9d58e | 595 | leak = memoryTable_.getNextLeak(leak, period); |
rgrover1 | 0:0b799af9d58e | 596 | } |
rgrover1 | 0:0b799af9d58e | 597 | |
rgrover1 | 0:0b799af9d58e | 598 | outputBuffer_.stopMemoryLeakReporting(); |
rgrover1 | 0:0b799af9d58e | 599 | } |
rgrover1 | 0:0b799af9d58e | 600 | |
rgrover1 | 0:0b799af9d58e | 601 | const char* MemoryLeakDetector::report(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 602 | { |
rgrover1 | 0:0b799af9d58e | 603 | outputBuffer_.clear(); |
rgrover1 | 0:0b799af9d58e | 604 | ConstructMemoryLeakReport(period); |
rgrover1 | 0:0b799af9d58e | 605 | |
rgrover1 | 0:0b799af9d58e | 606 | return outputBuffer_.toString(); |
rgrover1 | 0:0b799af9d58e | 607 | } |
rgrover1 | 0:0b799af9d58e | 608 | |
rgrover1 | 0:0b799af9d58e | 609 | void MemoryLeakDetector::markCheckingPeriodLeaksAsNonCheckingPeriod() |
rgrover1 | 0:0b799af9d58e | 610 | { |
rgrover1 | 0:0b799af9d58e | 611 | MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(mem_leak_period_checking); |
rgrover1 | 0:0b799af9d58e | 612 | while (leak) { |
rgrover1 | 0:0b799af9d58e | 613 | if (leak->period_ == mem_leak_period_checking) leak->period_ = mem_leak_period_enabled; |
rgrover1 | 0:0b799af9d58e | 614 | leak = memoryTable_.getNextLeak(leak, mem_leak_period_checking); |
rgrover1 | 0:0b799af9d58e | 615 | } |
rgrover1 | 0:0b799af9d58e | 616 | } |
rgrover1 | 0:0b799af9d58e | 617 | |
rgrover1 | 0:0b799af9d58e | 618 | int MemoryLeakDetector::totalMemoryLeaks(MemLeakPeriod period) |
rgrover1 | 0:0b799af9d58e | 619 | { |
rgrover1 | 0:0b799af9d58e | 620 | return memoryTable_.getTotalLeaks(period); |
rgrover1 | 0:0b799af9d58e | 621 | } |