Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MemoryLeakWarningPlugin.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 00028 #include "CppUTest/TestHarness.h" 00029 #include "CppUTest/MemoryLeakWarningPlugin.h" 00030 #include "CppUTest/MemoryLeakDetector.h" 00031 #include "CppUTest/TestMemoryAllocator.h" 00032 #include "CppUTest/PlatformSpecificFunctions.h" 00033 00034 /********** Enabling and disabling for C also *********/ 00035 00036 #if CPPUTEST_USE_MEM_LEAK_DETECTION 00037 00038 static void* mem_leak_malloc(size_t size, const char* file, int line) 00039 { 00040 return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentMallocAllocator(), size, file, line, true); 00041 } 00042 00043 static void mem_leak_free(void* buffer, const char* file, int line) 00044 { 00045 MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) buffer); 00046 MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentMallocAllocator(), (char*) buffer, file, line, true); 00047 } 00048 00049 static void* mem_leak_realloc(void* memory, size_t size, const char* file, int line) 00050 { 00051 return MemoryLeakWarningPlugin::getGlobalDetector()->reallocMemory(getCurrentMallocAllocator(), (char*) memory, size, file, line, true); 00052 } 00053 00054 #endif 00055 00056 static void* normal_malloc(size_t size, const char*, int) 00057 { 00058 return PlatformSpecificMalloc(size); 00059 } 00060 00061 static void* normal_realloc(void* memory, size_t size, const char*, int) 00062 { 00063 return PlatformSpecificRealloc(memory, size); 00064 } 00065 00066 static void normal_free(void* buffer, const char*, int) 00067 { 00068 PlatformSpecificFree(buffer); 00069 } 00070 00071 #if CPPUTEST_USE_MEM_LEAK_DETECTION 00072 static void *(*malloc_fptr)(size_t size, const char* file, int line) = mem_leak_malloc; 00073 static void (*free_fptr)(void* mem, const char* file, int line) = mem_leak_free; 00074 static void*(*realloc_fptr)(void* memory, size_t size, const char* file, int line) = mem_leak_realloc; 00075 #else 00076 static void *(*malloc_fptr)(size_t size, const char* file, int line) = normal_malloc; 00077 static void (*free_fptr)(void* mem, const char* file, int line) = normal_free; 00078 static void*(*realloc_fptr)(void* memory, size_t size, const char* file, int line) = normal_realloc; 00079 #endif 00080 00081 void* cpputest_malloc_location_with_leak_detection(size_t size, const char* file, int line) 00082 { 00083 return malloc_fptr(size, file, line); 00084 } 00085 00086 void* cpputest_realloc_location_with_leak_detection(void* memory, size_t size, const char* file, int line) 00087 { 00088 return realloc_fptr(memory, size, file, line); 00089 } 00090 00091 void cpputest_free_location_with_leak_detection(void* buffer, const char* file, int line) 00092 { 00093 free_fptr(buffer, file, line); 00094 } 00095 00096 /********** C++ *************/ 00097 00098 #if CPPUTEST_USE_MEM_LEAK_DETECTION 00099 #undef new 00100 00101 #if CPPUTEST_USE_STD_CPP_LIB 00102 #define UT_THROW_BAD_ALLOC_WHEN_NULL(memory) if (memory == NULL) throw std::bad_alloc(); 00103 #else 00104 #define UT_THROW_BAD_ALLOC_WHEN_NULL(memory) 00105 #endif 00106 00107 static void* mem_leak_operator_new (size_t size) UT_THROW(std::bad_alloc) 00108 { 00109 void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size); 00110 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00111 return memory; 00112 } 00113 00114 static void* mem_leak_operator_new_nothrow (size_t size) UT_NOTHROW 00115 { 00116 return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size); 00117 } 00118 00119 static void* mem_leak_operator_new_debug (size_t size, const char* file, int line) UT_THROW(std::bad_alloc) 00120 { 00121 void *memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewAllocator(), size, (char*) file, line); 00122 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00123 return memory; 00124 } 00125 00126 static void* mem_leak_operator_new_array (size_t size) UT_THROW(std::bad_alloc) 00127 { 00128 void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size); 00129 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00130 return memory; 00131 } 00132 00133 static void* mem_leak_operator_new_array_nothrow (size_t size) UT_NOTHROW 00134 { 00135 return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size); 00136 } 00137 00138 static void* mem_leak_operator_new_array_debug (size_t size, const char* file, int line) UT_THROW(std::bad_alloc) 00139 { 00140 void* memory = MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(getCurrentNewArrayAllocator(), size, (char*) file, line); 00141 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00142 return memory; 00143 } 00144 00145 static void mem_leak_operator_delete (void* mem) UT_NOTHROW 00146 { 00147 MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) mem); 00148 MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentNewAllocator(), (char*) mem); 00149 } 00150 00151 static void mem_leak_operator_delete_array (void* mem) UT_NOTHROW 00152 { 00153 MemoryLeakWarningPlugin::getGlobalDetector()->invalidateMemory((char*) mem); 00154 MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(getCurrentNewArrayAllocator(), (char*) mem); 00155 } 00156 00157 static void* normal_operator_new (size_t size) UT_THROW(std::bad_alloc) 00158 { 00159 void* memory = PlatformSpecificMalloc(size); 00160 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00161 return memory; 00162 } 00163 00164 static void* normal_operator_new_nothrow (size_t size) UT_NOTHROW 00165 { 00166 return PlatformSpecificMalloc(size); 00167 } 00168 00169 static void* normal_operator_new_debug (size_t size, const char* /*file*/, int /*line*/) UT_THROW(std::bad_alloc) 00170 { 00171 void* memory = PlatformSpecificMalloc(size); 00172 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00173 return memory; 00174 } 00175 00176 static void* normal_operator_new_array (size_t size) UT_THROW(std::bad_alloc) 00177 { 00178 void* memory = PlatformSpecificMalloc(size); 00179 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00180 return memory; 00181 } 00182 00183 static void* normal_operator_new_array_nothrow (size_t size) UT_NOTHROW 00184 { 00185 return PlatformSpecificMalloc(size); 00186 } 00187 00188 static void* normal_operator_new_array_debug (size_t size, const char* /*file*/, int /*line*/) UT_THROW(std::bad_alloc) 00189 { 00190 void* memory = PlatformSpecificMalloc(size); 00191 UT_THROW_BAD_ALLOC_WHEN_NULL(memory); 00192 return memory; 00193 } 00194 00195 static void normal_operator_delete (void* mem) UT_NOTHROW 00196 { 00197 PlatformSpecificFree(mem); 00198 } 00199 00200 static void normal_operator_delete_array (void* mem) UT_NOTHROW 00201 { 00202 PlatformSpecificFree(mem); 00203 } 00204 00205 static void *(*operator_new_fptr)(size_t size) UT_THROW(std::bad_alloc) = mem_leak_operator_new; 00206 static void *(*operator_new_nothrow_fptr)(size_t size) UT_NOTHROW = mem_leak_operator_new_nothrow; 00207 static void *(*operator_new_debug_fptr)(size_t size, const char* file, int line) UT_THROW(std::bad_alloc) = mem_leak_operator_new_debug; 00208 static void *(*operator_new_array_fptr)(size_t size) UT_THROW(std::bad_alloc) = mem_leak_operator_new_array; 00209 static void *(*operator_new_array_nothrow_fptr)(size_t size) UT_NOTHROW = mem_leak_operator_new_array_nothrow; 00210 static void *(*operator_new_array_debug_fptr)(size_t size, const char* file, int line) UT_THROW(std::bad_alloc) = mem_leak_operator_new_array_debug; 00211 static void (*operator_delete_fptr)(void* mem) UT_NOTHROW = mem_leak_operator_delete; 00212 static void (*operator_delete_array_fptr)(void* mem) UT_NOTHROW = mem_leak_operator_delete_array; 00213 00214 void* operator new(size_t size) UT_THROW(std::bad_alloc) 00215 { 00216 return operator_new_fptr(size); 00217 } 00218 00219 void* operator new(size_t size, const char* file, int line) UT_THROW(std::bad_alloc) 00220 { 00221 return operator_new_debug_fptr(size, file, line); 00222 } 00223 00224 void operator delete(void* mem) UT_NOTHROW 00225 { 00226 operator_delete_fptr(mem); 00227 } 00228 00229 void operator delete(void* mem, const char*, int) UT_NOTHROW 00230 { 00231 operator_delete_fptr(mem); 00232 } 00233 00234 void* operator new[](size_t size) UT_THROW(std::bad_alloc) 00235 { 00236 return operator_new_array_fptr(size); 00237 } 00238 00239 void* operator new [](size_t size, const char* file, int line) UT_THROW(std::bad_alloc) 00240 { 00241 return operator_new_array_debug_fptr(size, file, line); 00242 } 00243 00244 void operator delete[](void* mem) UT_NOTHROW 00245 { 00246 operator_delete_array_fptr(mem); 00247 } 00248 00249 void operator delete[](void* mem, const char*, int) UT_NOTHROW 00250 { 00251 operator_delete_array_fptr(mem); 00252 } 00253 00254 00255 #if CPPUTEST_USE_STD_CPP_LIB 00256 00257 void* operator new(size_t size, const std::nothrow_t&) UT_NOTHROW 00258 { 00259 return operator_new_nothrow_fptr(size); 00260 } 00261 00262 void* operator new[](size_t size, const std::nothrow_t&) UT_NOTHROW 00263 { 00264 return operator_new_array_nothrow_fptr(size); 00265 } 00266 00267 #else 00268 00269 /* Have a similar method. This avoid unused operator_new_nothrow_fptr warning */ 00270 00271 extern void* operator_new_nothrow(size_t size) UT_NOTHROW; 00272 extern void* operator_new_array_nothrow(size_t size) UT_NOTHROW; 00273 00274 void* operator_new_nothrow(size_t size) UT_NOTHROW 00275 { 00276 return operator_new_nothrow_fptr(size); 00277 } 00278 00279 void* operator_new_array_nothrow(size_t size) UT_NOTHROW 00280 { 00281 return operator_new_array_nothrow_fptr(size); 00282 } 00283 00284 #endif 00285 #endif 00286 00287 void MemoryLeakWarningPlugin::turnOffNewDeleteOverloads() 00288 { 00289 #if CPPUTEST_USE_MEM_LEAK_DETECTION 00290 operator_new_fptr = normal_operator_new; 00291 operator_new_nothrow_fptr = normal_operator_new_nothrow; 00292 operator_new_debug_fptr = normal_operator_new_debug; 00293 operator_new_array_fptr = normal_operator_new_array; 00294 operator_new_array_nothrow_fptr = normal_operator_new_array_nothrow; 00295 operator_new_array_debug_fptr = normal_operator_new_array_debug; 00296 operator_delete_fptr = normal_operator_delete; 00297 operator_delete_array_fptr = normal_operator_delete_array; 00298 malloc_fptr = normal_malloc; 00299 realloc_fptr = normal_realloc; 00300 free_fptr = normal_free; 00301 00302 #endif 00303 } 00304 00305 void MemoryLeakWarningPlugin::turnOnNewDeleteOverloads() 00306 { 00307 #if CPPUTEST_USE_MEM_LEAK_DETECTION 00308 operator_new_fptr = mem_leak_operator_new; 00309 operator_new_nothrow_fptr = mem_leak_operator_new_nothrow; 00310 operator_new_debug_fptr = mem_leak_operator_new_debug; 00311 operator_new_array_fptr = mem_leak_operator_new_array; 00312 operator_new_array_nothrow_fptr = mem_leak_operator_new_array_nothrow; 00313 operator_new_array_debug_fptr = mem_leak_operator_new_array_debug; 00314 operator_delete_fptr = mem_leak_operator_delete; 00315 operator_delete_array_fptr = mem_leak_operator_delete_array; 00316 malloc_fptr = mem_leak_malloc; 00317 realloc_fptr = mem_leak_realloc; 00318 free_fptr = mem_leak_free; 00319 #endif 00320 } 00321 00322 bool MemoryLeakWarningPlugin::areNewDeleteOverloaded() 00323 { 00324 #if CPPUTEST_USE_MEM_LEAK_DETECTION 00325 return operator_new_fptr == mem_leak_operator_new; 00326 #else 00327 return false; 00328 #endif 00329 } 00330 00331 void crash_on_allocation_number(unsigned alloc_number) 00332 { 00333 static CrashOnAllocationAllocator crashAllocator; 00334 crashAllocator.setNumberToCrashOn(alloc_number); 00335 setCurrentMallocAllocator(&crashAllocator); 00336 setCurrentNewAllocator(&crashAllocator); 00337 setCurrentNewArrayAllocator(&crashAllocator); 00338 } 00339 00340 class MemoryLeakWarningReporter: public MemoryLeakFailure 00341 { 00342 public: 00343 virtual ~MemoryLeakWarningReporter() 00344 { 00345 } 00346 00347 virtual void fail(char* fail_string) 00348 { 00349 UtestShell* currentTest = UtestShell::getCurrent(); 00350 currentTest->failWith(FailFailure(currentTest, currentTest->getName().asCharString(), currentTest->getLineNumber(), fail_string), TestTerminatorWithoutExceptions()); 00351 } 00352 }; 00353 00354 static MemoryLeakFailure* globalReporter = 0; 00355 static MemoryLeakDetector* globalDetector = 0; 00356 00357 MemoryLeakDetector* MemoryLeakWarningPlugin::getGlobalDetector() 00358 { 00359 if (globalDetector == 0) { 00360 bool newDeleteOverloaded = areNewDeleteOverloaded(); 00361 turnOffNewDeleteOverloads(); 00362 00363 globalReporter = new MemoryLeakWarningReporter; 00364 globalDetector = new MemoryLeakDetector(globalReporter); 00365 00366 if (newDeleteOverloaded) turnOnNewDeleteOverloads(); 00367 } 00368 return globalDetector; 00369 } 00370 00371 MemoryLeakFailure* MemoryLeakWarningPlugin::getGlobalFailureReporter() 00372 { 00373 return globalReporter; 00374 } 00375 00376 void MemoryLeakWarningPlugin::destroyGlobalDetectorAndTurnOffMemoryLeakDetectionInDestructor(bool des) 00377 { 00378 destroyGlobalDetectorAndTurnOfMemoryLeakDetectionInDestructor_ = des; 00379 } 00380 00381 void MemoryLeakWarningPlugin::setGlobalDetector(MemoryLeakDetector* detector, MemoryLeakFailure* reporter) 00382 { 00383 globalDetector = detector; 00384 globalReporter = reporter; 00385 } 00386 00387 void MemoryLeakWarningPlugin::destroyGlobalDetector() 00388 { 00389 turnOffNewDeleteOverloads(); 00390 delete globalDetector; 00391 delete globalReporter; 00392 globalDetector = NULL; 00393 } 00394 00395 00396 MemoryLeakWarningPlugin* MemoryLeakWarningPlugin::firstPlugin_ = 0; 00397 00398 MemoryLeakWarningPlugin* MemoryLeakWarningPlugin::getFirstPlugin() 00399 { 00400 return firstPlugin_; 00401 } 00402 00403 MemoryLeakDetector* MemoryLeakWarningPlugin::getMemoryLeakDetector() 00404 { 00405 return memLeakDetector_; 00406 } 00407 00408 void MemoryLeakWarningPlugin::ignoreAllLeaksInTest() 00409 { 00410 ignoreAllWarnings_ = true; 00411 } 00412 00413 void MemoryLeakWarningPlugin::expectLeaksInTest(int n) 00414 { 00415 expectedLeaks_ = n; 00416 } 00417 00418 MemoryLeakWarningPlugin::MemoryLeakWarningPlugin(const SimpleString& name, MemoryLeakDetector* localDetector) : 00419 TestPlugin(name), ignoreAllWarnings_(false), destroyGlobalDetectorAndTurnOfMemoryLeakDetectionInDestructor_(false), expectedLeaks_(0) 00420 { 00421 if (firstPlugin_ == 0) firstPlugin_ = this; 00422 00423 if (localDetector) memLeakDetector_ = localDetector; 00424 else memLeakDetector_ = getGlobalDetector(); 00425 00426 memLeakDetector_->enable(); 00427 } 00428 00429 MemoryLeakWarningPlugin::~MemoryLeakWarningPlugin() 00430 { 00431 if (destroyGlobalDetectorAndTurnOfMemoryLeakDetectionInDestructor_) { 00432 MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); 00433 MemoryLeakWarningPlugin::destroyGlobalDetector(); 00434 } 00435 } 00436 00437 void MemoryLeakWarningPlugin::preTestAction(UtestShell& /*test*/, TestResult& result) 00438 { 00439 memLeakDetector_->startChecking(); 00440 failureCount_ = result.getFailureCount(); 00441 } 00442 00443 void MemoryLeakWarningPlugin::postTestAction(UtestShell& test, TestResult& result) 00444 { 00445 memLeakDetector_->stopChecking(); 00446 int leaks = memLeakDetector_->totalMemoryLeaks(mem_leak_period_checking); 00447 00448 if (!ignoreAllWarnings_ && expectedLeaks_ != leaks && failureCount_ == result.getFailureCount()) { 00449 TestFailure f(&test, memLeakDetector_->report(mem_leak_period_checking)); 00450 result.addFailure(f); 00451 } 00452 memLeakDetector_->markCheckingPeriodLeaksAsNonCheckingPeriod(); 00453 ignoreAllWarnings_ = false; 00454 expectedLeaks_ = 0; 00455 } 00456 00457 const char* MemoryLeakWarningPlugin::FinalReport(int toBeDeletedLeaks) 00458 { 00459 int leaks = memLeakDetector_->totalMemoryLeaks(mem_leak_period_enabled); 00460 if (leaks != toBeDeletedLeaks) return memLeakDetector_->report(mem_leak_period_enabled); 00461 return ""; 00462 } 00463 00464
Generated on Fri Jul 15 2022 01:46:32 by
1.7.2