fork

Fork of cpputest by Rohit Grover

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MemoryLeakWarningPlugin.cpp Source File

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