|  | // Copyright (c) 2005, Google Inc. | 
|  | // All rights reserved. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above | 
|  | // copyright notice, this list of conditions and the following disclaimer | 
|  | // in the documentation and/or other materials provided with the | 
|  | // distribution. | 
|  | //     * Neither the name of Google Inc. nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  |  | 
|  | // --- | 
|  | // Author: Maxim Lifantsev | 
|  | // | 
|  | // Running: | 
|  | // ./heap-checker_unittest | 
|  | // | 
|  | // If the unittest crashes because it can't find pprof, try: | 
|  | // PPROF_PATH=/usr/local/someplace/bin/pprof ./heap-checker_unittest | 
|  | // | 
|  | // To test that the whole-program heap checker will actually cause a leak, try: | 
|  | // HEAPCHECK_TEST_LEAK= ./heap-checker_unittest | 
|  | // HEAPCHECK_TEST_LOOP_LEAK= ./heap-checker_unittest | 
|  | // | 
|  | // Note: Both of the above commands *should* abort with an error message. | 
|  |  | 
|  | // CAVEAT: Do not use vector<> and string on-heap objects in this test, | 
|  | // otherwise the test can sometimes fail for tricky leak checks | 
|  | // when we want some allocated object not to be found live by the heap checker. | 
|  | // This can happen with memory allocators like tcmalloc that can allocate | 
|  | // heap objects back to back without any book-keeping data in between. | 
|  | // What happens is that end-of-storage pointers of a live vector | 
|  | // (or a string depending on the STL implementation used) | 
|  | // can happen to point to that other heap-allocated | 
|  | // object that is not reachable otherwise and that | 
|  | // we don't want to be reachable. | 
|  | // | 
|  | // The implication of this for real leak checking | 
|  | // is just one more chance for the liveness flood to be inexact | 
|  | // (see the comment in our .h file). | 
|  |  | 
|  | #include "config_for_unittests.h" | 
|  | #ifdef HAVE_POLL_H | 
|  | #include <poll.h> | 
|  | #endif | 
|  | #if defined HAVE_STDINT_H | 
|  | #include <stdint.h>             // to get uint16_t (ISO naming madness) | 
|  | #elif defined HAVE_INTTYPES_H | 
|  | #include <inttypes.h>           // another place uint16_t might be defined | 
|  | #endif | 
|  | #include <sys/types.h> | 
|  | #include <stdlib.h> | 
|  | #include <errno.h>              // errno | 
|  | #ifdef HAVE_UNISTD_H | 
|  | #include <unistd.h>             // for sleep(), geteuid() | 
|  | #endif | 
|  | #ifdef HAVE_MMAP | 
|  | #include <sys/mman.h> | 
|  | #endif | 
|  | #include <fcntl.h>              // for open(), close() | 
|  | #ifdef HAVE_EXECINFO_H | 
|  | #include <execinfo.h>           // backtrace | 
|  | #endif | 
|  | #ifdef HAVE_GRP_H | 
|  | #include <grp.h>                // getgrent, getgrnam | 
|  | #endif | 
|  | #ifdef HAVE_PWD_H | 
|  | #include <pwd.h> | 
|  | #endif | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <iostream>             // for cout | 
|  | #include <iomanip>              // for hex | 
|  | #include <list> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/commandlineflags.h" | 
|  | #include "base/googleinit.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/commandlineflags.h" | 
|  | #include "base/thread_lister.h" | 
|  | #include <gperftools/heap-checker.h> | 
|  | #include "memory_region_map.h" | 
|  | #include <gperftools/malloc_extension.h> | 
|  | #include <gperftools/stacktrace.h> | 
|  |  | 
|  | // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old | 
|  | // form of the name instead. | 
|  | #ifndef MAP_ANONYMOUS | 
|  | # define MAP_ANONYMOUS MAP_ANON | 
|  | #endif | 
|  |  | 
|  | using namespace std; | 
|  |  | 
|  | // ========================================================================= // | 
|  |  | 
|  | // TODO(maxim): write a shell script to test that these indeed crash us | 
|  | //              (i.e. we do detect leaks) | 
|  | //              Maybe add more such crash tests. | 
|  |  | 
|  | DEFINE_bool(test_leak, | 
|  | EnvToBool("HEAP_CHECKER_TEST_TEST_LEAK", false), | 
|  | "If should cause a leak crash"); | 
|  | DEFINE_bool(test_loop_leak, | 
|  | EnvToBool("HEAP_CHECKER_TEST_TEST_LOOP_LEAK", false), | 
|  | "If should cause a looped leak crash"); | 
|  | DEFINE_bool(test_register_leak, | 
|  | EnvToBool("HEAP_CHECKER_TEST_TEST_REGISTER_LEAK", false), | 
|  | "If should cause a leak crash by hiding a pointer " | 
|  | "that is only in a register"); | 
|  | DEFINE_bool(test_cancel_global_check, | 
|  | EnvToBool("HEAP_CHECKER_TEST_TEST_CANCEL_GLOBAL_CHECK", false), | 
|  | "If should test HeapLeakChecker::CancelGlobalCheck " | 
|  | "when --test_leak or --test_loop_leak are given; " | 
|  | "the test should not fail then"); | 
|  | DEFINE_bool(maybe_stripped, | 
|  | EnvToBool("HEAP_CHECKER_TEST_MAYBE_STRIPPED", true), | 
|  | "If we think we can be a stripped binary"); | 
|  | DEFINE_bool(interfering_threads, | 
|  | EnvToBool("HEAP_CHECKER_TEST_INTERFERING_THREADS", true), | 
|  | "If we should use threads trying " | 
|  | "to interfere with leak checking"); | 
|  | DEFINE_bool(hoarding_threads, | 
|  | EnvToBool("HEAP_CHECKER_TEST_HOARDING_THREADS", true), | 
|  | "If threads (usually the manager thread) are known " | 
|  | "to retain some old state in their global buffers, " | 
|  | "so that it's hard to force leaks when threads are around"); | 
|  | // TODO(maxim): Chage the default to false | 
|  | // when the standard environment used NTPL threads: | 
|  | // they do not seem to have this problem. | 
|  | DEFINE_bool(no_threads, | 
|  | EnvToBool("HEAP_CHECKER_TEST_NO_THREADS", false), | 
|  | "If we should not use any threads"); | 
|  | // This is used so we can make can_create_leaks_reliably true | 
|  | // for any pthread implementation and test with that. | 
|  |  | 
|  | DECLARE_int64(heap_check_max_pointer_offset);   // heap-checker.cc | 
|  | DECLARE_string(heap_check);  // in heap-checker.cc | 
|  |  | 
|  | #define WARN_IF(cond, msg)   LOG_IF(WARNING, cond, msg) | 
|  |  | 
|  | // This is an evil macro!  Be very careful using it... | 
|  | #undef VLOG          // and we start by evilling overriding logging.h VLOG | 
|  | #define VLOG(lvl)    if (FLAGS_verbose >= (lvl))  cout << "\n" | 
|  | // This is, likewise, evil | 
|  | #define LOGF         VLOG(INFO) | 
|  |  | 
|  | static void RunHeapBusyThreads();  // below | 
|  |  | 
|  |  | 
|  | class Closure { | 
|  | public: | 
|  | virtual ~Closure() { } | 
|  | virtual void Run() = 0; | 
|  | }; | 
|  |  | 
|  | class Callback0 : public Closure { | 
|  | public: | 
|  | typedef void (*FunctionSignature)(); | 
|  |  | 
|  | inline Callback0(FunctionSignature f) : f_(f) {} | 
|  | virtual void Run() { (*f_)(); delete this; } | 
|  |  | 
|  | private: | 
|  | FunctionSignature f_; | 
|  | }; | 
|  |  | 
|  | template <class P1> class Callback1 : public Closure { | 
|  | public: | 
|  | typedef void (*FunctionSignature)(P1); | 
|  |  | 
|  | inline Callback1<P1>(FunctionSignature f, P1 p1) : f_(f), p1_(p1) {} | 
|  | virtual void Run() { (*f_)(p1_); delete this; } | 
|  |  | 
|  | private: | 
|  | FunctionSignature f_; | 
|  | P1 p1_; | 
|  | }; | 
|  |  | 
|  | template <class P1, class P2> class Callback2 : public Closure { | 
|  | public: | 
|  | typedef void (*FunctionSignature)(P1,P2); | 
|  |  | 
|  | inline Callback2<P1,P2>(FunctionSignature f, P1 p1, P2 p2) : f_(f), p1_(p1), p2_(p2) {} | 
|  | virtual void Run() { (*f_)(p1_, p2_); delete this; } | 
|  |  | 
|  | private: | 
|  | FunctionSignature f_; | 
|  | P1 p1_; | 
|  | P2 p2_; | 
|  | }; | 
|  |  | 
|  | inline Callback0* NewCallback(void (*function)()) { | 
|  | return new Callback0(function); | 
|  | } | 
|  |  | 
|  | template <class P1> | 
|  | inline Callback1<P1>* NewCallback(void (*function)(P1), P1 p1) { | 
|  | return new Callback1<P1>(function, p1); | 
|  | } | 
|  |  | 
|  | template <class P1, class P2> | 
|  | inline Callback2<P1,P2>* NewCallback(void (*function)(P1,P2), P1 p1, P2 p2) { | 
|  | return new Callback2<P1,P2>(function, p1, p2); | 
|  | } | 
|  |  | 
|  |  | 
|  | // Set to true at end of main, so threads know.  Not entirely thread-safe!, | 
|  | // but probably good enough. | 
|  | static bool g_have_exited_main = false; | 
|  |  | 
|  | // If we can reliably create leaks (i.e. make leaked object | 
|  | // really unreachable from any global data). | 
|  | static bool can_create_leaks_reliably = false; | 
|  |  | 
|  | // We use a simple allocation wrapper | 
|  | // to make sure we wipe out the newly allocated objects | 
|  | // in case they still happened to contain some pointer data | 
|  | // accidentally left by the memory allocator. | 
|  | struct Initialized { }; | 
|  | static Initialized initialized; | 
|  | void* operator new(size_t size, const Initialized&) { | 
|  | // Below we use "p = new(initialized) Foo[1];" and  "delete[] p;" | 
|  | // instead of "p = new(initialized) Foo;" | 
|  | // when we need to delete an allocated object. | 
|  | void* p = malloc(size); | 
|  | memset(p, 0, size); | 
|  | return p; | 
|  | } | 
|  | void* operator new[](size_t size, const Initialized&) { | 
|  | char* p = new char[size]; | 
|  | memset(p, 0, size); | 
|  | return p; | 
|  | } | 
|  |  | 
|  | static void DoWipeStack(int n);  // defined below | 
|  | static void WipeStack() { DoWipeStack(20); } | 
|  |  | 
|  | static void Pause() { | 
|  | poll(NULL, 0, 77);  // time for thread activity in HeapBusyThreadBody | 
|  |  | 
|  | // Indirectly test malloc_extension.*: | 
|  | CHECK(MallocExtension::instance()->VerifyAllMemory()); | 
|  | int blocks; | 
|  | size_t total; | 
|  | int histogram[kMallocHistogramSize]; | 
|  | if (MallocExtension::instance() | 
|  | ->MallocMemoryStats(&blocks, &total, histogram)  &&  total != 0) { | 
|  | VLOG(3) << "Malloc stats: " << blocks << " blocks of " | 
|  | << total << " bytes"; | 
|  | for (int i = 0; i < kMallocHistogramSize; ++i) { | 
|  | if (histogram[i]) { | 
|  | VLOG(3) << "  Malloc histogram at " << i << " : " << histogram[i]; | 
|  | } | 
|  | } | 
|  | } | 
|  | WipeStack();  // e.g. MallocExtension::VerifyAllMemory | 
|  | // can leave pointers to heap objects on stack | 
|  | } | 
|  |  | 
|  | // Make gcc think a pointer is "used" | 
|  | template <class T> | 
|  | static void Use(T** foo) { | 
|  | VLOG(2) << "Dummy-using " << static_cast<void*>(*foo) << " at " << foo; | 
|  | } | 
|  |  | 
|  | // Arbitrary value, but not such that xor'ing with it is likely | 
|  | // to map one valid pointer to another valid pointer: | 
|  | static const uintptr_t kHideMask = | 
|  | static_cast<uintptr_t>(0xF03A5F7BF03A5F7BLL); | 
|  |  | 
|  | // Helpers to hide a pointer from live data traversal. | 
|  | // We just xor the pointer so that (with high probability) | 
|  | // it's not a valid address of a heap object anymore. | 
|  | // Both Hide and UnHide must be executed within RunHidden() below | 
|  | // to prevent leaving stale data on active stack that can be a pointer | 
|  | // to a heap object that is not actually reachable via live variables. | 
|  | // (UnHide might leave heap pointer value for an object | 
|  | //  that will be deallocated but later another object | 
|  | //  can be allocated at the same heap address.) | 
|  | template <class T> | 
|  | static void Hide(T** ptr) { | 
|  | // we cast values, not dereferenced pointers, so no aliasing issues: | 
|  | *ptr = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(*ptr) ^ kHideMask); | 
|  | VLOG(2) << "hid: " << static_cast<void*>(*ptr); | 
|  | } | 
|  |  | 
|  | template <class T> | 
|  | static void UnHide(T** ptr) { | 
|  | VLOG(2) << "unhiding: " << static_cast<void*>(*ptr); | 
|  | // we cast values, not dereferenced pointers, so no aliasing issues: | 
|  | *ptr = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(*ptr) ^ kHideMask); | 
|  | } | 
|  |  | 
|  | static void LogHidden(const char* message, const void* ptr) { | 
|  | LOGF << message << " : " | 
|  | << ptr << " ^ " << reinterpret_cast<void*>(kHideMask) << endl; | 
|  | } | 
|  |  | 
|  | // volatile to fool the compiler against inlining the calls to these | 
|  | void (*volatile run_hidden_ptr)(Closure* c, int n); | 
|  | void (*volatile wipe_stack_ptr)(int n); | 
|  |  | 
|  | static void DoRunHidden(Closure* c, int n) { | 
|  | if (n) { | 
|  | VLOG(10) << "Level " << n << " at " << &n; | 
|  | (*run_hidden_ptr)(c, n-1); | 
|  | (*wipe_stack_ptr)(n); | 
|  | sleep(0);  // undo -foptimize-sibling-calls | 
|  | } else { | 
|  | c->Run(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /*static*/ void DoWipeStack(int n) { | 
|  | VLOG(10) << "Wipe level " << n << " at " << &n; | 
|  | if (n) { | 
|  | const int sz = 30; | 
|  | volatile int arr[sz]; | 
|  | for (int i = 0; i < sz; ++i) arr[i] = 0; | 
|  | (*wipe_stack_ptr)(n-1); | 
|  | sleep(0);  // undo -foptimize-sibling-calls | 
|  | } | 
|  | } | 
|  |  | 
|  | // This executes closure c several stack frames down from the current one | 
|  | // and then makes an effort to also wipe out the stack data that was used by | 
|  | // the closure. | 
|  | // This way we prevent leak checker from finding any temporary pointers | 
|  | // of the closure execution on the stack and deciding that | 
|  | // these pointers (and the pointed objects) are still live. | 
|  | static void RunHidden(Closure* c) { | 
|  | DoRunHidden(c, 15); | 
|  | DoWipeStack(20); | 
|  | } | 
|  |  | 
|  | static void DoAllocHidden(size_t size, void** ptr) { | 
|  | void* p = new(initialized) char[size]; | 
|  | Hide(&p); | 
|  | Use(&p);  // use only hidden versions | 
|  | VLOG(2) << "Allocated hidden " << p << " at " << &p; | 
|  | *ptr = p;  // assign the hidden versions | 
|  | } | 
|  |  | 
|  | static void* AllocHidden(size_t size) { | 
|  | void* r; | 
|  | RunHidden(NewCallback(DoAllocHidden, size, &r)); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static void DoDeAllocHidden(void** ptr) { | 
|  | Use(ptr);  // use only hidden versions | 
|  | void* p = *ptr; | 
|  | VLOG(2) << "Deallocating hidden " << p; | 
|  | UnHide(&p); | 
|  | delete [] reinterpret_cast<char*>(p); | 
|  | } | 
|  |  | 
|  | static void DeAllocHidden(void** ptr) { | 
|  | RunHidden(NewCallback(DoDeAllocHidden, ptr)); | 
|  | *ptr = NULL; | 
|  | Use(ptr); | 
|  | } | 
|  |  | 
|  | void PreventHeapReclaiming(size_t size) { | 
|  | #ifdef NDEBUG | 
|  | if (true) { | 
|  | static void** no_reclaim_list = NULL; | 
|  | CHECK(size >= sizeof(void*)); | 
|  | // We can't use malloc_reclaim_memory flag in opt mode as debugallocation.cc | 
|  | // is not used. Instead we allocate a bunch of heap objects that are | 
|  | // of the same size as what we are going to leak to ensure that the object | 
|  | // we are about to leak is not at the same address as some old allocated | 
|  | // and freed object that might still have pointers leading to it. | 
|  | for (int i = 0; i < 100; ++i) { | 
|  | void** p = reinterpret_cast<void**>(new(initialized) char[size]); | 
|  | p[0] = no_reclaim_list; | 
|  | no_reclaim_list = p; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static bool RunSilent(HeapLeakChecker* check, | 
|  | bool (HeapLeakChecker::* func)()) { | 
|  | // By default, don't print the 'we detected a leak' message in the | 
|  | // cases we're expecting a leak (we still print when --v is >= 1). | 
|  | // This way, the logging output is less confusing: we only print | 
|  | // "we detected a leak", and how to diagnose it, for *unexpected* leaks. | 
|  | int32 old_FLAGS_verbose = FLAGS_verbose; | 
|  | if (!VLOG_IS_ON(1))             // not on a verbose setting | 
|  | FLAGS_verbose = FATAL;        // only log fatal errors | 
|  | const bool retval = (check->*func)(); | 
|  | FLAGS_verbose = old_FLAGS_verbose; | 
|  | return retval; | 
|  | } | 
|  |  | 
|  | #define RUN_SILENT(check, func)  RunSilent(&(check), &HeapLeakChecker::func) | 
|  |  | 
|  | enum CheckType { SAME_HEAP, NO_LEAKS }; | 
|  |  | 
|  | static void VerifyLeaks(HeapLeakChecker* check, CheckType type, | 
|  | int leaked_bytes, int leaked_objects) { | 
|  | WipeStack();  // to help with can_create_leaks_reliably | 
|  | const bool no_leaks = | 
|  | type == NO_LEAKS ? RUN_SILENT(*check, BriefNoLeaks) | 
|  | : RUN_SILENT(*check, BriefSameHeap); | 
|  | if (can_create_leaks_reliably) { | 
|  | // these might still fail occasionally, but it should be very rare | 
|  | CHECK_EQ(no_leaks, false); | 
|  | CHECK_EQ(check->BytesLeaked(), leaked_bytes); | 
|  | CHECK_EQ(check->ObjectsLeaked(), leaked_objects); | 
|  | } else { | 
|  | WARN_IF(no_leaks != false, | 
|  | "Expected leaks not found: " | 
|  | "Some liveness flood must be too optimistic"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // not deallocates | 
|  | static void TestHeapLeakCheckerDeathSimple() { | 
|  | HeapLeakChecker check("death_simple"); | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | void* bar = AllocHidden(300); | 
|  | Use(&bar); | 
|  | LogHidden("Leaking", foo); | 
|  | LogHidden("Leaking", bar); | 
|  | Pause(); | 
|  | VerifyLeaks(&check, NO_LEAKS, 300 + 100 * sizeof(int), 2); | 
|  | DeAllocHidden(&foo); | 
|  | DeAllocHidden(&bar); | 
|  | } | 
|  |  | 
|  | static void MakeDeathLoop(void** arr1, void** arr2) { | 
|  | PreventHeapReclaiming(2 * sizeof(void*)); | 
|  | void** a1 = new(initialized) void*[2]; | 
|  | void** a2 = new(initialized) void*[2]; | 
|  | a1[1] = reinterpret_cast<void*>(a2); | 
|  | a2[1] = reinterpret_cast<void*>(a1); | 
|  | Hide(&a1); | 
|  | Hide(&a2); | 
|  | Use(&a1); | 
|  | Use(&a2); | 
|  | VLOG(2) << "Made hidden loop at " << &a1 << " to " << arr1; | 
|  | *arr1 = a1; | 
|  | *arr2 = a2; | 
|  | } | 
|  |  | 
|  | // not deallocates two objects linked together | 
|  | static void TestHeapLeakCheckerDeathLoop() { | 
|  | HeapLeakChecker check("death_loop"); | 
|  | void* arr1; | 
|  | void* arr2; | 
|  | RunHidden(NewCallback(MakeDeathLoop, &arr1, &arr2)); | 
|  | Use(&arr1); | 
|  | Use(&arr2); | 
|  | LogHidden("Leaking", arr1); | 
|  | LogHidden("Leaking", arr2); | 
|  | Pause(); | 
|  | VerifyLeaks(&check, NO_LEAKS, 4 * sizeof(void*), 2); | 
|  | DeAllocHidden(&arr1); | 
|  | DeAllocHidden(&arr2); | 
|  | } | 
|  |  | 
|  | // deallocates more than allocates | 
|  | static void TestHeapLeakCheckerDeathInverse() { | 
|  | void* bar = AllocHidden(250 * sizeof(int)); | 
|  | Use(&bar); | 
|  | LogHidden("Pre leaking", bar); | 
|  | Pause(); | 
|  | HeapLeakChecker check("death_inverse"); | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | LogHidden("Leaking", foo); | 
|  | DeAllocHidden(&bar); | 
|  | Pause(); | 
|  | VerifyLeaks(&check, SAME_HEAP, | 
|  | 100 * static_cast<int64>(sizeof(int)), | 
|  | 1); | 
|  | DeAllocHidden(&foo); | 
|  | } | 
|  |  | 
|  | // deallocates more than allocates | 
|  | static void TestHeapLeakCheckerDeathNoLeaks() { | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | void* bar = AllocHidden(250 * sizeof(int)); | 
|  | Use(&bar); | 
|  | HeapLeakChecker check("death_noleaks"); | 
|  | DeAllocHidden(&bar); | 
|  | CHECK_EQ(check.BriefNoLeaks(), true); | 
|  | DeAllocHidden(&foo); | 
|  | } | 
|  |  | 
|  | // have less objecs | 
|  | static void TestHeapLeakCheckerDeathCountLess() { | 
|  | void* bar1 = AllocHidden(50 * sizeof(int)); | 
|  | Use(&bar1); | 
|  | void* bar2 = AllocHidden(50 * sizeof(int)); | 
|  | Use(&bar2); | 
|  | LogHidden("Pre leaking", bar1); | 
|  | LogHidden("Pre leaking", bar2); | 
|  | Pause(); | 
|  | HeapLeakChecker check("death_count_less"); | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | LogHidden("Leaking", foo); | 
|  | DeAllocHidden(&bar1); | 
|  | DeAllocHidden(&bar2); | 
|  | Pause(); | 
|  | VerifyLeaks(&check, SAME_HEAP, | 
|  | 100 * sizeof(int), | 
|  | 1); | 
|  | DeAllocHidden(&foo); | 
|  | } | 
|  |  | 
|  | // have more objecs | 
|  | static void TestHeapLeakCheckerDeathCountMore() { | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | LogHidden("Pre leaking", foo); | 
|  | Pause(); | 
|  | HeapLeakChecker check("death_count_more"); | 
|  | void* bar1 = AllocHidden(50 * sizeof(int)); | 
|  | Use(&bar1); | 
|  | void* bar2 = AllocHidden(50 * sizeof(int)); | 
|  | Use(&bar2); | 
|  | LogHidden("Leaking", bar1); | 
|  | LogHidden("Leaking", bar2); | 
|  | DeAllocHidden(&foo); | 
|  | Pause(); | 
|  | VerifyLeaks(&check, SAME_HEAP, | 
|  | 100 * sizeof(int), | 
|  | 2); | 
|  | DeAllocHidden(&bar1); | 
|  | DeAllocHidden(&bar2); | 
|  | } | 
|  |  | 
|  | static void TestHiddenPointer() { | 
|  | int i; | 
|  | void* foo = &i; | 
|  | HiddenPointer<void> p(foo); | 
|  | CHECK_EQ(foo, p.get()); | 
|  |  | 
|  | // Confirm pointer doesn't appear to contain a byte sequence | 
|  | // that == the pointer.  We don't really need to test that | 
|  | // the xor trick itself works, as without it nothing in this | 
|  | // test suite would work.  See the Hide/Unhide/*Hidden* set | 
|  | // of helper methods. | 
|  | CHECK_NE(foo, *reinterpret_cast<void**>(&p)); | 
|  | } | 
|  |  | 
|  | // simple tests that deallocate what they allocated | 
|  | static void TestHeapLeakChecker() { | 
|  | { HeapLeakChecker check("trivial"); | 
|  | int foo = 5; | 
|  | int* p = &foo; | 
|  | Use(&p); | 
|  | Pause(); | 
|  | CHECK(check.BriefSameHeap()); | 
|  | } | 
|  | Pause(); | 
|  | { HeapLeakChecker check("simple"); | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | void* bar = AllocHidden(200 * sizeof(int)); | 
|  | Use(&bar); | 
|  | DeAllocHidden(&foo); | 
|  | DeAllocHidden(&bar); | 
|  | Pause(); | 
|  | CHECK(check.BriefSameHeap()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // no false positives | 
|  | static void TestHeapLeakCheckerNoFalsePositives() { | 
|  | { HeapLeakChecker check("trivial_p"); | 
|  | int foo = 5; | 
|  | int* p = &foo; | 
|  | Use(&p); | 
|  | Pause(); | 
|  | CHECK(check.BriefSameHeap()); | 
|  | } | 
|  | Pause(); | 
|  | { HeapLeakChecker check("simple_p"); | 
|  | void* foo = AllocHidden(100 * sizeof(int)); | 
|  | Use(&foo); | 
|  | void* bar = AllocHidden(200 * sizeof(int)); | 
|  | Use(&bar); | 
|  | DeAllocHidden(&foo); | 
|  | DeAllocHidden(&bar); | 
|  | Pause(); | 
|  | CHECK(check.SameHeap()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // test that we detect leaks when we have same total # of bytes and | 
|  | // objects, but different individual object sizes | 
|  | static void TestLeakButTotalsMatch() { | 
|  | void* bar1 = AllocHidden(240 * sizeof(int)); | 
|  | Use(&bar1); | 
|  | void* bar2 = AllocHidden(160 * sizeof(int)); | 
|  | Use(&bar2); | 
|  | LogHidden("Pre leaking", bar1); | 
|  | LogHidden("Pre leaking", bar2); | 
|  | Pause(); | 
|  | HeapLeakChecker check("trick"); | 
|  | void* foo1 = AllocHidden(280 * sizeof(int)); | 
|  | Use(&foo1); | 
|  | void* foo2 = AllocHidden(120 * sizeof(int)); | 
|  | Use(&foo2); | 
|  | LogHidden("Leaking", foo1); | 
|  | LogHidden("Leaking", foo2); | 
|  | DeAllocHidden(&bar1); | 
|  | DeAllocHidden(&bar2); | 
|  | Pause(); | 
|  |  | 
|  | // foo1 and foo2 leaked | 
|  | VerifyLeaks(&check, NO_LEAKS, (280+120)*sizeof(int), 2); | 
|  |  | 
|  | DeAllocHidden(&foo1); | 
|  | DeAllocHidden(&foo2); | 
|  | } | 
|  |  | 
|  | // no false negatives from pprof | 
|  | static void TestHeapLeakCheckerDeathTrick() { | 
|  | void* bar1 = AllocHidden(240 * sizeof(int)); | 
|  | Use(&bar1); | 
|  | void* bar2 = AllocHidden(160 * sizeof(int)); | 
|  | Use(&bar2); | 
|  | HeapLeakChecker check("death_trick"); | 
|  | DeAllocHidden(&bar1); | 
|  | DeAllocHidden(&bar2); | 
|  | void* foo1 = AllocHidden(280 * sizeof(int)); | 
|  | Use(&foo1); | 
|  | void* foo2 = AllocHidden(120 * sizeof(int)); | 
|  | Use(&foo2); | 
|  | // TODO(maxim): use the above if we make pprof work in automated test runs | 
|  | if (!FLAGS_maybe_stripped) { | 
|  | CHECK_EQ(RUN_SILENT(check, SameHeap), false); | 
|  | // pprof checking should catch the leak | 
|  | } else { | 
|  | WARN_IF(RUN_SILENT(check, SameHeap) != false, | 
|  | "death_trick leak is not caught; " | 
|  | "we must be using a stripped binary"); | 
|  | } | 
|  | DeAllocHidden(&foo1); | 
|  | DeAllocHidden(&foo2); | 
|  | } | 
|  |  | 
|  | // simple leak | 
|  | static void TransLeaks() { | 
|  | AllocHidden(1 * sizeof(char)); | 
|  | } | 
|  |  | 
|  | // range-based disabling using Disabler | 
|  | static void ScopedDisabledLeaks() { | 
|  | HeapLeakChecker::Disabler disabler; | 
|  | AllocHidden(3 * sizeof(int)); | 
|  | TransLeaks(); | 
|  | (void)malloc(10);  // Direct leak | 
|  | } | 
|  |  | 
|  | // have different disabled leaks | 
|  | static void* RunDisabledLeaks(void* a) { | 
|  | ScopedDisabledLeaks(); | 
|  | return a; | 
|  | } | 
|  |  | 
|  | // have different disabled leaks inside of a thread | 
|  | static void ThreadDisabledLeaks() { | 
|  | if (FLAGS_no_threads)  return; | 
|  | pthread_t tid; | 
|  | pthread_attr_t attr; | 
|  | CHECK_EQ(pthread_attr_init(&attr), 0); | 
|  | CHECK_EQ(pthread_create(&tid, &attr, RunDisabledLeaks, NULL), 0); | 
|  | void* res; | 
|  | CHECK_EQ(pthread_join(tid, &res), 0); | 
|  | } | 
|  |  | 
|  | // different disabled leaks (some in threads) | 
|  | static void TestHeapLeakCheckerDisabling() { | 
|  | HeapLeakChecker check("disabling"); | 
|  |  | 
|  | RunDisabledLeaks(NULL); | 
|  | RunDisabledLeaks(NULL); | 
|  | ThreadDisabledLeaks(); | 
|  | RunDisabledLeaks(NULL); | 
|  | ThreadDisabledLeaks(); | 
|  | ThreadDisabledLeaks(); | 
|  |  | 
|  | Pause(); | 
|  |  | 
|  | CHECK(check.SameHeap()); | 
|  | } | 
|  |  | 
|  | typedef set<int> IntSet; | 
|  |  | 
|  | static int some_ints[] = { 1, 2, 3, 21, 22, 23, 24, 25 }; | 
|  |  | 
|  | static void DoTestSTLAlloc() { | 
|  | IntSet* x = new(initialized) IntSet[1]; | 
|  | *x = IntSet(some_ints, some_ints + 6); | 
|  | for (int i = 0; i < 1000; i++) { | 
|  | x->insert(i*3); | 
|  | } | 
|  | delete [] x; | 
|  | } | 
|  |  | 
|  | // Check that normal STL usage does not result in a leak report. | 
|  | // (In particular we test that there's no complex STL's own allocator | 
|  | // running on top of our allocator with hooks to heap profiler | 
|  | // that can result in false leak report in this case.) | 
|  | static void TestSTLAlloc() { | 
|  | HeapLeakChecker check("stl"); | 
|  | RunHidden(NewCallback(DoTestSTLAlloc)); | 
|  | CHECK_EQ(check.BriefSameHeap(), true); | 
|  | } | 
|  |  | 
|  | static void DoTestSTLAllocInverse(IntSet** setx) { | 
|  | IntSet* x = new(initialized) IntSet[1]; | 
|  | *x = IntSet(some_ints, some_ints + 3); | 
|  | for (int i = 0; i < 100; i++) { | 
|  | x->insert(i*2); | 
|  | } | 
|  | Hide(&x); | 
|  | *setx = x; | 
|  | } | 
|  |  | 
|  | static void FreeTestSTLAllocInverse(IntSet** setx) { | 
|  | IntSet* x = *setx; | 
|  | UnHide(&x); | 
|  | delete [] x; | 
|  | } | 
|  |  | 
|  | // Check that normal leaked STL usage *does* result in a leak report. | 
|  | // (In particular we test that there's no complex STL's own allocator | 
|  | // running on top of our allocator with hooks to heap profiler | 
|  | // that can result in false absence of leak report in this case.) | 
|  | static void TestSTLAllocInverse() { | 
|  | HeapLeakChecker check("death_inverse_stl"); | 
|  | IntSet* x; | 
|  | RunHidden(NewCallback(DoTestSTLAllocInverse, &x)); | 
|  | LogHidden("Leaking", x); | 
|  | if (can_create_leaks_reliably) { | 
|  | WipeStack();  // to help with can_create_leaks_reliably | 
|  | // these might still fail occasionally, but it should be very rare | 
|  | CHECK_EQ(RUN_SILENT(check, BriefNoLeaks), false); | 
|  | CHECK_GE(check.BytesLeaked(), 100 * sizeof(int)); | 
|  | CHECK_GE(check.ObjectsLeaked(), 100); | 
|  | // assumes set<>s are represented by some kind of binary tree | 
|  | // or something else allocating >=1 heap object per set object | 
|  | } else { | 
|  | WARN_IF(RUN_SILENT(check, BriefNoLeaks) != false, | 
|  | "Expected leaks not found: " | 
|  | "Some liveness flood must be too optimistic"); | 
|  | } | 
|  | RunHidden(NewCallback(FreeTestSTLAllocInverse, &x)); | 
|  | } | 
|  |  | 
|  | template<class Alloc> | 
|  | static void DirectTestSTLAlloc(Alloc allocator, const char* name) { | 
|  | HeapLeakChecker check((string("direct_stl-") + name).c_str()); | 
|  | static const int kSize = 1000; | 
|  | typename Alloc::pointer ptrs[kSize]; | 
|  | for (int i = 0; i < kSize; ++i) { | 
|  | typename Alloc::pointer p = allocator.allocate(i*3+1); | 
|  | HeapLeakChecker::IgnoreObject(p); | 
|  | // This will crash if p is not known to heap profiler: | 
|  | // (i.e. STL's "allocator" does not have a direct hook to heap profiler) | 
|  | HeapLeakChecker::UnIgnoreObject(p); | 
|  | ptrs[i] = p; | 
|  | } | 
|  | for (int i = 0; i < kSize; ++i) { | 
|  | allocator.deallocate(ptrs[i], i*3+1); | 
|  | ptrs[i] = NULL; | 
|  | } | 
|  | CHECK(check.BriefSameHeap());  // just in case | 
|  | } | 
|  |  | 
|  | static struct group* grp = NULL; | 
|  | static const int kKeys = 50; | 
|  | static pthread_key_t key[kKeys]; | 
|  |  | 
|  | static void KeyFree(void* ptr) { | 
|  | delete [] reinterpret_cast<char*>(ptr); | 
|  | } | 
|  |  | 
|  | static bool key_init_has_run = false; | 
|  |  | 
|  | static void KeyInit() { | 
|  | for (int i = 0; i < kKeys; ++i) { | 
|  | CHECK_EQ(pthread_key_create(&key[i], KeyFree), 0); | 
|  | VLOG(2) << "pthread key " << i << " : " << key[i]; | 
|  | } | 
|  | key_init_has_run = true;   // needed for a sanity-check | 
|  | } | 
|  |  | 
|  | // force various C library static and thread-specific allocations | 
|  | static void TestLibCAllocate() { | 
|  | CHECK(key_init_has_run); | 
|  | for (int i = 0; i < kKeys; ++i) { | 
|  | void* p = pthread_getspecific(key[i]); | 
|  | if (NULL == p) { | 
|  | if (i == 0) { | 
|  | // Test-logging inside threads which (potentially) creates and uses | 
|  | // thread-local data inside standard C++ library: | 
|  | VLOG(0) << "Adding pthread-specifics for thread " << pthread_self() | 
|  | << " pid " << getpid(); | 
|  | } | 
|  | p = new(initialized) char[77 + i]; | 
|  | VLOG(2) << "pthread specific " << i << " : " << p; | 
|  | pthread_setspecific(key[i], p); | 
|  | } | 
|  | } | 
|  |  | 
|  | strerror(errno); | 
|  | const time_t now = time(NULL); | 
|  | ctime(&now); | 
|  | #ifdef HAVE_EXECINFO_H | 
|  | void *stack[1]; | 
|  | backtrace(stack, 1); | 
|  | #endif | 
|  | #ifdef HAVE_GRP_H | 
|  | gid_t gid = getgid(); | 
|  | getgrgid(gid); | 
|  | if (grp == NULL)  grp = getgrent();  // a race condition here is okay | 
|  | getgrnam(grp->gr_name); | 
|  | #endif | 
|  | #ifdef HAVE_PWD_H | 
|  | getpwuid(geteuid()); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | // Continuous random heap memory activity to try to disrupt heap checking. | 
|  | static void* HeapBusyThreadBody(void* a) { | 
|  | const int thread_num = reinterpret_cast<intptr_t>(a); | 
|  | VLOG(0) << "A new HeapBusyThread " << thread_num; | 
|  | TestLibCAllocate(); | 
|  |  | 
|  | int user = 0; | 
|  | // Try to hide ptr from heap checker in a CPU register: | 
|  | // Here we are just making a best effort to put the only pointer | 
|  | // to a heap object into a thread register to test | 
|  | // the thread-register finding machinery in the heap checker. | 
|  | #if defined(__i386__) && defined(__GNUC__) | 
|  | register int** ptr asm("esi"); | 
|  | #elif defined(__x86_64__) && defined(__GNUC__) | 
|  | register int** ptr asm("r15"); | 
|  | #else | 
|  | register int** ptr; | 
|  | #endif | 
|  | ptr = NULL; | 
|  | typedef set<int> Set; | 
|  | Set s1; | 
|  | while (1) { | 
|  | // TestLibCAllocate() calls libc functions that don't work so well | 
|  | // after main() has exited.  So we just don't do the test then. | 
|  | if (!g_have_exited_main) | 
|  | TestLibCAllocate(); | 
|  |  | 
|  | if (ptr == NULL) { | 
|  | ptr = new(initialized) int*[1]; | 
|  | *ptr = new(initialized) int[1]; | 
|  | } | 
|  | set<int>* s2 = new(initialized) set<int>[1]; | 
|  | s1.insert(random()); | 
|  | s2->insert(*s1.begin()); | 
|  | user += *s2->begin(); | 
|  | **ptr += user; | 
|  | if (random() % 51 == 0) { | 
|  | s1.clear(); | 
|  | if (random() % 2 == 0) { | 
|  | s1.~Set(); | 
|  | new(&s1) Set; | 
|  | } | 
|  | } | 
|  | VLOG(3) << pthread_self() << " (" << getpid() << "): in wait: " | 
|  | << ptr << ", " << *ptr << "; " << s1.size(); | 
|  | VLOG(2) << pthread_self() << " (" << getpid() << "): in wait, ptr = " | 
|  | << reinterpret_cast<void*>( | 
|  | reinterpret_cast<uintptr_t>(ptr) ^ kHideMask) | 
|  | << "^" << reinterpret_cast<void*>(kHideMask); | 
|  | if (FLAGS_test_register_leak  &&  thread_num % 5 == 0) { | 
|  | // Hide the register "ptr" value with an xor mask. | 
|  | // If one provides --test_register_leak flag, the test should | 
|  | // (with very high probability) crash on some leak check | 
|  | // with a leak report (of some x * sizeof(int) + y * sizeof(int*) bytes) | 
|  | // pointing at the two lines above in this function | 
|  | // with "new(initialized) int" in them as the allocators | 
|  | // of the leaked objects. | 
|  | // CAVEAT: We can't really prevent a compiler to save some | 
|  | // temporary values of "ptr" on the stack and thus let us find | 
|  | // the heap objects not via the register. | 
|  | // Hence it's normal if for certain compilers or optimization modes | 
|  | // --test_register_leak does not cause a leak crash of the above form | 
|  | // (this happens e.g. for gcc 4.0.1 in opt mode). | 
|  | ptr = reinterpret_cast<int **>( | 
|  | reinterpret_cast<uintptr_t>(ptr) ^ kHideMask); | 
|  | // busy loop to get the thread interrupted at: | 
|  | for (int i = 1; i < 10000000; ++i)  user += (1 + user * user * 5) / i; | 
|  | ptr = reinterpret_cast<int **>( | 
|  | reinterpret_cast<uintptr_t>(ptr) ^ kHideMask); | 
|  | } else { | 
|  | poll(NULL, 0, random() % 100); | 
|  | } | 
|  | VLOG(2) << pthread_self() << ": continuing"; | 
|  | if (random() % 3 == 0) { | 
|  | delete [] *ptr; | 
|  | delete [] ptr; | 
|  | ptr = NULL; | 
|  | } | 
|  | delete [] s2; | 
|  | } | 
|  | return a; | 
|  | } | 
|  |  | 
|  | static void RunHeapBusyThreads() { | 
|  | KeyInit(); | 
|  | if (!FLAGS_interfering_threads || FLAGS_no_threads)  return; | 
|  |  | 
|  | const int n = 17;  // make many threads | 
|  |  | 
|  | pthread_t tid; | 
|  | pthread_attr_t attr; | 
|  | CHECK_EQ(pthread_attr_init(&attr), 0); | 
|  | // make them and let them run | 
|  | for (int i = 0; i < n; ++i) { | 
|  | VLOG(0) << "Creating extra thread " << i + 1; | 
|  | CHECK(pthread_create(&tid, &attr, HeapBusyThreadBody, | 
|  | reinterpret_cast<void*>(i)) == 0); | 
|  | } | 
|  |  | 
|  | Pause(); | 
|  | Pause(); | 
|  | } | 
|  |  | 
|  | // ========================================================================= // | 
|  |  | 
|  | // This code section is to test that objects that are reachable from global | 
|  | // variables are not reported as leaks | 
|  | // as well as that (Un)IgnoreObject work for such objects fine. | 
|  |  | 
|  | // An object making functions: | 
|  | // returns a "weird" pointer to a new object for which | 
|  | // it's worth checking that the object is reachable via that pointer. | 
|  | typedef void* (*ObjMakerFunc)(); | 
|  | static list<ObjMakerFunc> obj_makers;  // list of registered object makers | 
|  |  | 
|  | // Helper macro to register an object making function | 
|  | // 'name' is an identifier of this object maker, | 
|  | // 'body' is its function body that must declare | 
|  | //        pointer 'p' to the nex object to return. | 
|  | // Usage example: | 
|  | //   REGISTER_OBJ_MAKER(trivial, int* p = new(initialized) int;) | 
|  | #define REGISTER_OBJ_MAKER(name, body) \ | 
|  | void* ObjMaker_##name##_() { \ | 
|  | VLOG(1) << "Obj making " << #name; \ | 
|  | body; \ | 
|  | return p; \ | 
|  | } \ | 
|  | static ObjMakerRegistrar maker_reg_##name##__(&ObjMaker_##name##_); | 
|  | // helper class for REGISTER_OBJ_MAKER | 
|  | struct ObjMakerRegistrar { | 
|  | ObjMakerRegistrar(ObjMakerFunc obj_maker) { obj_makers.push_back(obj_maker); } | 
|  | }; | 
|  |  | 
|  | // List of the objects/pointers made with all the obj_makers | 
|  | // to test reachability via global data pointers during leak checks. | 
|  | static list<void*>* live_objects = new list<void*>; | 
|  | // pointer so that it does not get destructed on exit | 
|  |  | 
|  | // Exerciser for one ObjMakerFunc. | 
|  | static void TestPointerReach(ObjMakerFunc obj_maker) { | 
|  | HeapLeakChecker::IgnoreObject(obj_maker());  // test IgnoreObject | 
|  |  | 
|  | void* obj = obj_maker(); | 
|  | HeapLeakChecker::IgnoreObject(obj); | 
|  | HeapLeakChecker::UnIgnoreObject(obj);  // test UnIgnoreObject | 
|  | HeapLeakChecker::IgnoreObject(obj);  // not to need deletion for obj | 
|  |  | 
|  | live_objects->push_back(obj_maker());  // test reachability at leak check | 
|  | } | 
|  |  | 
|  | // Test all ObjMakerFunc registred via REGISTER_OBJ_MAKER. | 
|  | static void TestObjMakers() { | 
|  | for (list<ObjMakerFunc>::const_iterator i = obj_makers.begin(); | 
|  | i != obj_makers.end(); ++i) { | 
|  | TestPointerReach(*i); | 
|  | TestPointerReach(*i);  // a couple more times would not hurt | 
|  | TestPointerReach(*i); | 
|  | } | 
|  | } | 
|  |  | 
|  | // A dummy class to mimic allocation behavior of string-s. | 
|  | template<class T> | 
|  | struct Array { | 
|  | Array() { | 
|  | size = 3 + random() % 30; | 
|  | ptr = new(initialized) T[size]; | 
|  | } | 
|  | ~Array() { delete [] ptr; } | 
|  | Array(const Array& x) { | 
|  | size = x.size; | 
|  | ptr = new(initialized) T[size]; | 
|  | for (size_t i = 0; i < size; ++i) { | 
|  | ptr[i] = x.ptr[i]; | 
|  | } | 
|  | } | 
|  | void operator=(const Array& x) { | 
|  | delete [] ptr; | 
|  | size = x.size; | 
|  | ptr = new(initialized) T[size]; | 
|  | for (size_t i = 0; i < size; ++i) { | 
|  | ptr[i] = x.ptr[i]; | 
|  | } | 
|  | } | 
|  | void append(const Array& x) { | 
|  | T* p = new(initialized) T[size + x.size]; | 
|  | for (size_t i = 0; i < size; ++i) { | 
|  | p[i] = ptr[i]; | 
|  | } | 
|  | for (size_t i = 0; i < x.size; ++i) { | 
|  | p[size+i] = x.ptr[i]; | 
|  | } | 
|  | size += x.size; | 
|  | delete [] ptr; | 
|  | ptr = p; | 
|  | } | 
|  | private: | 
|  | size_t size; | 
|  | T* ptr; | 
|  | }; | 
|  |  | 
|  | // to test pointers to objects, built-in arrays, string, etc: | 
|  | REGISTER_OBJ_MAKER(plain, int* p = new(initialized) int;) | 
|  | REGISTER_OBJ_MAKER(int_array_1, int* p = new(initialized) int[1];) | 
|  | REGISTER_OBJ_MAKER(int_array, int* p = new(initialized) int[10];) | 
|  | REGISTER_OBJ_MAKER(string, Array<char>* p = new(initialized) Array<char>();) | 
|  | REGISTER_OBJ_MAKER(string_array, | 
|  | Array<char>* p = new(initialized) Array<char>[5];) | 
|  | REGISTER_OBJ_MAKER(char_array, char* p = new(initialized) char[5];) | 
|  | REGISTER_OBJ_MAKER(appended_string, | 
|  | Array<char>* p = new Array<char>(); | 
|  | p->append(Array<char>()); | 
|  | ) | 
|  | REGISTER_OBJ_MAKER(plain_ptr, int** p = new(initialized) int*;) | 
|  | REGISTER_OBJ_MAKER(linking_ptr, | 
|  | int** p = new(initialized) int*; | 
|  | *p = new(initialized) int; | 
|  | ) | 
|  |  | 
|  | // small objects: | 
|  | REGISTER_OBJ_MAKER(0_sized, void* p = malloc(0);)  // 0-sized object (important) | 
|  | REGISTER_OBJ_MAKER(1_sized, void* p = malloc(1);) | 
|  | REGISTER_OBJ_MAKER(2_sized, void* p = malloc(2);) | 
|  | REGISTER_OBJ_MAKER(3_sized, void* p = malloc(3);) | 
|  | REGISTER_OBJ_MAKER(4_sized, void* p = malloc(4);) | 
|  |  | 
|  | static int set_data[] = { 1, 2, 3, 4, 5, 6, 7, 21, 22, 23, 24, 25, 26, 27 }; | 
|  | static set<int> live_leak_set(set_data, set_data+7); | 
|  | static const set<int> live_leak_const_set(set_data, set_data+14); | 
|  |  | 
|  | REGISTER_OBJ_MAKER(set, | 
|  | set<int>* p = new(initialized) set<int>(set_data, set_data + 13); | 
|  | ) | 
|  |  | 
|  | class ClassA { | 
|  | public: | 
|  | explicit ClassA(int a) : ptr(NULL) { } | 
|  | mutable char* ptr; | 
|  | }; | 
|  | static const ClassA live_leak_mutable(1); | 
|  |  | 
|  | template<class C> | 
|  | class TClass { | 
|  | public: | 
|  | explicit TClass(int a) : ptr(NULL) { } | 
|  | mutable C val; | 
|  | mutable C* ptr; | 
|  | }; | 
|  | static const TClass<Array<char> > live_leak_templ_mutable(1); | 
|  |  | 
|  | class ClassB { | 
|  | public: | 
|  | ClassB() { } | 
|  | char b[7]; | 
|  | virtual void f() { } | 
|  | virtual ~ClassB() { } | 
|  | }; | 
|  |  | 
|  | class ClassB2 { | 
|  | public: | 
|  | ClassB2() { } | 
|  | char b2[11]; | 
|  | virtual void f2() { } | 
|  | virtual ~ClassB2() { } | 
|  | }; | 
|  |  | 
|  | class ClassD1 : public ClassB { | 
|  | char d1[15]; | 
|  | virtual void f() { } | 
|  | }; | 
|  |  | 
|  | class ClassD2 : public ClassB2 { | 
|  | char d2[19]; | 
|  | virtual void f2() { } | 
|  | }; | 
|  |  | 
|  | class ClassD : public ClassD1, public ClassD2 { | 
|  | char d[3]; | 
|  | virtual void f() { } | 
|  | virtual void f2() { } | 
|  | }; | 
|  |  | 
|  | // to test pointers to objects of base subclasses: | 
|  |  | 
|  | REGISTER_OBJ_MAKER(B,  ClassB*  p = new(initialized) ClassB;) | 
|  | REGISTER_OBJ_MAKER(D1, ClassD1* p = new(initialized) ClassD1;) | 
|  | REGISTER_OBJ_MAKER(D2, ClassD2* p = new(initialized) ClassD2;) | 
|  | REGISTER_OBJ_MAKER(D,  ClassD*  p = new(initialized) ClassD;) | 
|  |  | 
|  | REGISTER_OBJ_MAKER(D1_as_B,  ClassB*  p = new(initialized) ClassD1;) | 
|  | REGISTER_OBJ_MAKER(D2_as_B2, ClassB2* p = new(initialized) ClassD2;) | 
|  | REGISTER_OBJ_MAKER(D_as_B,   ClassB*  p = new(initialized)  ClassD;) | 
|  | REGISTER_OBJ_MAKER(D_as_D1,  ClassD1* p = new(initialized) ClassD;) | 
|  | // inside-object pointers: | 
|  | REGISTER_OBJ_MAKER(D_as_B2,  ClassB2* p = new(initialized) ClassD;) | 
|  | REGISTER_OBJ_MAKER(D_as_D2,  ClassD2* p = new(initialized) ClassD;) | 
|  |  | 
|  | class InterfaceA { | 
|  | public: | 
|  | virtual void A() = 0; | 
|  | virtual ~InterfaceA() { } | 
|  | protected: | 
|  | InterfaceA() { } | 
|  | }; | 
|  |  | 
|  | class InterfaceB { | 
|  | public: | 
|  | virtual void B() = 0; | 
|  | virtual ~InterfaceB() { } | 
|  | protected: | 
|  | InterfaceB() { } | 
|  | }; | 
|  |  | 
|  | class InterfaceC : public InterfaceA { | 
|  | public: | 
|  | virtual void C() = 0; | 
|  | virtual ~InterfaceC() { } | 
|  | protected: | 
|  | InterfaceC() { } | 
|  | }; | 
|  |  | 
|  | class ClassMltD1 : public ClassB, public InterfaceB, public InterfaceC { | 
|  | public: | 
|  | char d1[11]; | 
|  | virtual void f() { } | 
|  | virtual void A() { } | 
|  | virtual void B() { } | 
|  | virtual void C() { } | 
|  | }; | 
|  |  | 
|  | class ClassMltD2 : public InterfaceA, public InterfaceB, public ClassB { | 
|  | public: | 
|  | char d2[15]; | 
|  | virtual void f() { } | 
|  | virtual void A() { } | 
|  | virtual void B() { } | 
|  | }; | 
|  |  | 
|  | // to specifically test heap reachability under | 
|  | // inerface-only multiple inheritance (some use inside-object pointers): | 
|  | REGISTER_OBJ_MAKER(MltD1,       ClassMltD1* p = new(initialized) ClassMltD1;) | 
|  | REGISTER_OBJ_MAKER(MltD1_as_B,  ClassB*     p = new(initialized) ClassMltD1;) | 
|  | REGISTER_OBJ_MAKER(MltD1_as_IA, InterfaceA* p = new(initialized) ClassMltD1;) | 
|  | REGISTER_OBJ_MAKER(MltD1_as_IB, InterfaceB* p = new(initialized) ClassMltD1;) | 
|  | REGISTER_OBJ_MAKER(MltD1_as_IC, InterfaceC* p = new(initialized) ClassMltD1;) | 
|  |  | 
|  | REGISTER_OBJ_MAKER(MltD2,       ClassMltD2* p = new(initialized) ClassMltD2;) | 
|  | REGISTER_OBJ_MAKER(MltD2_as_B,  ClassB*     p = new(initialized) ClassMltD2;) | 
|  | REGISTER_OBJ_MAKER(MltD2_as_IA, InterfaceA* p = new(initialized) ClassMltD2;) | 
|  | REGISTER_OBJ_MAKER(MltD2_as_IB, InterfaceB* p = new(initialized) ClassMltD2;) | 
|  |  | 
|  | // to mimic UnicodeString defined in third_party/icu, | 
|  | // which store a platform-independent-sized refcount in the first | 
|  | // few bytes and keeps a pointer pointing behind the refcount. | 
|  | REGISTER_OBJ_MAKER(unicode_string, | 
|  | char* p = new char[sizeof(uint32) * 10]; | 
|  | p += sizeof(uint32); | 
|  | ) | 
|  | // similar, but for platform-dependent-sized refcount | 
|  | REGISTER_OBJ_MAKER(ref_counted, | 
|  | char* p = new char[sizeof(int) * 20]; | 
|  | p += sizeof(int); | 
|  | ) | 
|  |  | 
|  | struct Nesting { | 
|  | struct Inner { | 
|  | Nesting* parent; | 
|  | Inner(Nesting* p) : parent(p) {} | 
|  | }; | 
|  | Inner i0; | 
|  | char n1[5]; | 
|  | Inner i1; | 
|  | char n2[11]; | 
|  | Inner i2; | 
|  | char n3[27]; | 
|  | Inner i3; | 
|  | Nesting() : i0(this), i1(this), i2(this), i3(this) {} | 
|  | }; | 
|  |  | 
|  | // to test inside-object pointers pointing at objects nested into heap objects: | 
|  | REGISTER_OBJ_MAKER(nesting_i0, Nesting::Inner* p = &((new Nesting())->i0);) | 
|  | REGISTER_OBJ_MAKER(nesting_i1, Nesting::Inner* p = &((new Nesting())->i1);) | 
|  | REGISTER_OBJ_MAKER(nesting_i2, Nesting::Inner* p = &((new Nesting())->i2);) | 
|  | REGISTER_OBJ_MAKER(nesting_i3, Nesting::Inner* p = &((new Nesting())->i3);) | 
|  |  | 
|  | // allocate many objects reachable from global data | 
|  | static void TestHeapLeakCheckerLiveness() { | 
|  | live_leak_mutable.ptr = new(initialized) char[77]; | 
|  | live_leak_templ_mutable.ptr = new(initialized) Array<char>(); | 
|  | live_leak_templ_mutable.val = Array<char>(); | 
|  |  | 
|  | TestObjMakers(); | 
|  | } | 
|  |  | 
|  | // ========================================================================= // | 
|  |  | 
|  | // Get address (PC value) following the mmap call into addr_after_mmap_call | 
|  | static void* Mmapper(uintptr_t* addr_after_mmap_call) { | 
|  | void* r = mmap(NULL, 100, PROT_READ|PROT_WRITE, | 
|  | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | 
|  | // Get current PC value into addr_after_mmap_call | 
|  | void* stack[1]; | 
|  | CHECK_EQ(GetStackTrace(stack, 1, 0), 1); | 
|  | *addr_after_mmap_call = reinterpret_cast<uintptr_t>(stack[0]); | 
|  | sleep(0);  // undo -foptimize-sibling-calls | 
|  | return r; | 
|  | } | 
|  |  | 
|  | // to trick complier into preventing inlining | 
|  | static void* (*mmapper_addr)(uintptr_t* addr) = &Mmapper; | 
|  |  | 
|  | // TODO(maxim): copy/move this to memory_region_map_unittest | 
|  | // TODO(maxim): expand this test to include mmap64, mremap and sbrk calls. | 
|  | static void VerifyMemoryRegionMapStackGet() { | 
|  | uintptr_t caller_addr_limit; | 
|  | void* addr = (*mmapper_addr)(&caller_addr_limit); | 
|  | uintptr_t caller = 0; | 
|  | { MemoryRegionMap::LockHolder l; | 
|  | for (MemoryRegionMap::RegionIterator | 
|  | i = MemoryRegionMap::BeginRegionLocked(); | 
|  | i != MemoryRegionMap::EndRegionLocked(); ++i) { | 
|  | if (i->start_addr == reinterpret_cast<uintptr_t>(addr)) { | 
|  | CHECK_EQ(caller, 0); | 
|  | caller = i->caller(); | 
|  | } | 
|  | } | 
|  | } | 
|  | // caller must point into Mmapper function: | 
|  | if (!(reinterpret_cast<uintptr_t>(mmapper_addr) <= caller  && | 
|  | caller < caller_addr_limit)) { | 
|  | LOGF << std::hex << "0x" << caller | 
|  | << " does not seem to point into code of function Mmapper at " | 
|  | << "0x" << reinterpret_cast<uintptr_t>(mmapper_addr) | 
|  | << "! Stack frame collection must be off in MemoryRegionMap!"; | 
|  | LOG(FATAL, "\n"); | 
|  | } | 
|  | munmap(addr, 100); | 
|  | } | 
|  |  | 
|  | static void* Mallocer(uintptr_t* addr_after_malloc_call) { | 
|  | void* r = malloc(100); | 
|  | sleep(0);  // undo -foptimize-sibling-calls | 
|  | // Get current PC value into addr_after_malloc_call | 
|  | void* stack[1]; | 
|  | CHECK_EQ(GetStackTrace(stack, 1, 0), 1); | 
|  | *addr_after_malloc_call = reinterpret_cast<uintptr_t>(stack[0]); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | // to trick complier into preventing inlining | 
|  | static void* (*mallocer_addr)(uintptr_t* addr) = &Mallocer; | 
|  |  | 
|  | // non-static for friendship with HeapProfiler | 
|  | // TODO(maxim): expand this test to include | 
|  | // realloc, calloc, memalign, valloc, pvalloc, new, and new[]. | 
|  | extern void VerifyHeapProfileTableStackGet() { | 
|  | uintptr_t caller_addr_limit; | 
|  | void* addr = (*mallocer_addr)(&caller_addr_limit); | 
|  | uintptr_t caller = | 
|  | reinterpret_cast<uintptr_t>(HeapLeakChecker::GetAllocCaller(addr)); | 
|  | // caller must point into Mallocer function: | 
|  | if (!(reinterpret_cast<uintptr_t>(mallocer_addr) <= caller  && | 
|  | caller < caller_addr_limit)) { | 
|  | LOGF << std::hex << "0x" << caller | 
|  | << " does not seem to point into code of function Mallocer at " | 
|  | << "0x" << reinterpret_cast<uintptr_t>(mallocer_addr) | 
|  | << "! Stack frame collection must be off in heap profiler!"; | 
|  | LOG(FATAL, "\n"); | 
|  | } | 
|  | free(addr); | 
|  | } | 
|  |  | 
|  | // ========================================================================= // | 
|  |  | 
|  | static void MakeALeak(void** arr) { | 
|  | PreventHeapReclaiming(10 * sizeof(int)); | 
|  | void* a = new(initialized) int[10]; | 
|  | Hide(&a); | 
|  | *arr = a; | 
|  | } | 
|  |  | 
|  | // Helper to do 'return 0;' inside main(): insted we do 'return Pass();' | 
|  | static int Pass() { | 
|  | fprintf(stdout, "PASS\n"); | 
|  | g_have_exited_main = true; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int main(int argc, char** argv) { | 
|  | run_hidden_ptr = DoRunHidden; | 
|  | wipe_stack_ptr = DoWipeStack; | 
|  | if (!HeapLeakChecker::IsActive()) { | 
|  | CHECK_EQ(FLAGS_heap_check, ""); | 
|  | LOG(WARNING, "HeapLeakChecker got turned off; we won't test much..."); | 
|  | } else { | 
|  | VerifyMemoryRegionMapStackGet(); | 
|  | VerifyHeapProfileTableStackGet(); | 
|  | } | 
|  |  | 
|  | KeyInit(); | 
|  |  | 
|  | // glibc 2.4, on x86_64 at least, has a lock-ordering bug, which | 
|  | // means deadlock is possible when one thread calls dl_open at the | 
|  | // same time another thread is calling dl_iterate_phdr.  libunwind | 
|  | // calls dl_iterate_phdr, and TestLibCAllocate calls dl_open (or the | 
|  | // various syscalls in it do), at least the first time it's run. | 
|  | // To avoid the deadlock, we run TestLibCAllocate once before getting | 
|  | // multi-threaded. | 
|  | // TODO(csilvers): once libc is fixed, or libunwind can work around it, | 
|  | //                 get rid of this early call.  We *want* our test to | 
|  | //                 find potential problems like this one! | 
|  | TestLibCAllocate(); | 
|  |  | 
|  | if (FLAGS_interfering_threads) { | 
|  | RunHeapBusyThreads();  // add interference early | 
|  | } | 
|  | TestLibCAllocate(); | 
|  |  | 
|  | LOGF << "In main(): heap_check=" << FLAGS_heap_check << endl; | 
|  |  | 
|  | CHECK(HeapLeakChecker::NoGlobalLeaks());  // so far, so good | 
|  |  | 
|  | if (FLAGS_test_leak) { | 
|  | void* arr; | 
|  | RunHidden(NewCallback(MakeALeak, &arr)); | 
|  | Use(&arr); | 
|  | LogHidden("Leaking", arr); | 
|  | if (FLAGS_test_cancel_global_check) { | 
|  | HeapLeakChecker::CancelGlobalCheck(); | 
|  | } else { | 
|  | // Verify we can call NoGlobalLeaks repeatedly without deadlocking | 
|  | HeapLeakChecker::NoGlobalLeaks(); | 
|  | HeapLeakChecker::NoGlobalLeaks(); | 
|  | } | 
|  | return Pass(); | 
|  | // whole-program leak-check should (with very high probability) | 
|  | // catch the leak of arr (10 * sizeof(int) bytes) | 
|  | // (when !FLAGS_test_cancel_global_check) | 
|  | } | 
|  |  | 
|  | if (FLAGS_test_loop_leak) { | 
|  | void* arr1; | 
|  | void* arr2; | 
|  | RunHidden(NewCallback(MakeDeathLoop, &arr1, &arr2)); | 
|  | Use(&arr1); | 
|  | Use(&arr2); | 
|  | LogHidden("Loop leaking", arr1); | 
|  | LogHidden("Loop leaking", arr2); | 
|  | if (FLAGS_test_cancel_global_check) { | 
|  | HeapLeakChecker::CancelGlobalCheck(); | 
|  | } else { | 
|  | // Verify we can call NoGlobalLeaks repeatedly without deadlocking | 
|  | HeapLeakChecker::NoGlobalLeaks(); | 
|  | HeapLeakChecker::NoGlobalLeaks(); | 
|  | } | 
|  | return Pass(); | 
|  | // whole-program leak-check should (with very high probability) | 
|  | // catch the leak of arr1 and arr2 (4 * sizeof(void*) bytes) | 
|  | // (when !FLAGS_test_cancel_global_check) | 
|  | } | 
|  |  | 
|  | if (FLAGS_test_register_leak) { | 
|  | // make us fail only where the .sh test expects: | 
|  | Pause(); | 
|  | for (int i = 0; i < 100; ++i) {  // give it some time to crash | 
|  | CHECK(HeapLeakChecker::NoGlobalLeaks()); | 
|  | Pause(); | 
|  | } | 
|  | return Pass(); | 
|  | } | 
|  |  | 
|  | TestHeapLeakCheckerLiveness(); | 
|  |  | 
|  | HeapLeakChecker heap_check("all"); | 
|  |  | 
|  | TestHiddenPointer(); | 
|  |  | 
|  | TestHeapLeakChecker(); | 
|  | Pause(); | 
|  | TestLeakButTotalsMatch(); | 
|  | Pause(); | 
|  |  | 
|  | TestHeapLeakCheckerDeathSimple(); | 
|  | Pause(); | 
|  | TestHeapLeakCheckerDeathLoop(); | 
|  | Pause(); | 
|  | TestHeapLeakCheckerDeathInverse(); | 
|  | Pause(); | 
|  | TestHeapLeakCheckerDeathNoLeaks(); | 
|  | Pause(); | 
|  | TestHeapLeakCheckerDeathCountLess(); | 
|  | Pause(); | 
|  | TestHeapLeakCheckerDeathCountMore(); | 
|  | Pause(); | 
|  |  | 
|  | TestHeapLeakCheckerDeathTrick(); | 
|  | Pause(); | 
|  |  | 
|  | CHECK(HeapLeakChecker::NoGlobalLeaks());  // so far, so good | 
|  |  | 
|  | TestHeapLeakCheckerNoFalsePositives(); | 
|  | Pause(); | 
|  |  | 
|  | TestHeapLeakCheckerDisabling(); | 
|  | Pause(); | 
|  |  | 
|  | TestSTLAlloc(); | 
|  | Pause(); | 
|  | TestSTLAllocInverse(); | 
|  | Pause(); | 
|  |  | 
|  | // Test that various STL allocators work.  Some of these are redundant, but | 
|  | // we don't know how STL might change in the future.  For example, | 
|  | // http://wiki/Main/StringNeStdString. | 
|  | #define DTSL(a) { DirectTestSTLAlloc(a, #a); \ | 
|  | Pause(); } | 
|  | DTSL(std::allocator<char>()); | 
|  | DTSL(std::allocator<int>()); | 
|  | DTSL(std::string().get_allocator()); | 
|  | DTSL(string().get_allocator()); | 
|  | DTSL(vector<int>().get_allocator()); | 
|  | DTSL(vector<double>().get_allocator()); | 
|  | DTSL(vector<vector<int> >().get_allocator()); | 
|  | DTSL(vector<string>().get_allocator()); | 
|  | DTSL((map<string, string>().get_allocator())); | 
|  | DTSL((map<string, int>().get_allocator())); | 
|  | DTSL(set<char>().get_allocator()); | 
|  | #undef DTSL | 
|  |  | 
|  | TestLibCAllocate(); | 
|  | Pause(); | 
|  |  | 
|  | CHECK(HeapLeakChecker::NoGlobalLeaks());  // so far, so good | 
|  |  | 
|  | Pause(); | 
|  |  | 
|  | if (!FLAGS_maybe_stripped) { | 
|  | CHECK(heap_check.SameHeap()); | 
|  | } else { | 
|  | WARN_IF(heap_check.SameHeap() != true, | 
|  | "overall leaks are caught; we must be using a stripped binary"); | 
|  | } | 
|  |  | 
|  | CHECK(HeapLeakChecker::NoGlobalLeaks());  // so far, so good | 
|  |  | 
|  | return Pass(); | 
|  | } |