fork
Fork of cpputest by
Embed:
(wiki syntax)
Show/hide line numbers
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 Tue Jul 12 2022 21:37:56 by 1.7.2