1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_DEBUG_LEAK_TRACKER_H_ 6 #define BASE_DEBUG_LEAK_TRACKER_H_ 7 8 #include <stddef.h> 9 10 #include "build/build_config.h" 11 12 // Only enable leak tracking in non-uClibc debug builds. 13 #if !defined(NDEBUG) && !defined(__UCLIBC__) 14 #define ENABLE_LEAK_TRACKER 15 #endif 16 17 #ifdef ENABLE_LEAK_TRACKER 18 #include "base/containers/linked_list.h" 19 #include "base/debug/stack_trace.h" 20 #include "base/logging.h" 21 #endif // ENABLE_LEAK_TRACKER 22 23 // LeakTracker is a helper to verify that all instances of a class 24 // have been destroyed. 25 // 26 // It is particularly useful for classes that are bound to a single thread -- 27 // before destroying that thread, one can check that there are no remaining 28 // instances of that class. 29 // 30 // For example, to enable leak tracking for class net::URLRequest, start by 31 // adding a member variable of type LeakTracker<net::URLRequest>. 32 // 33 // class URLRequest { 34 // ... 35 // private: 36 // base::LeakTracker<URLRequest> leak_tracker_; 37 // }; 38 // 39 // 40 // Next, when we believe all instances of net::URLRequest have been deleted: 41 // 42 // LeakTracker<net::URLRequest>::CheckForLeaks(); 43 // 44 // Should the check fail (because there are live instances of net::URLRequest), 45 // then the allocation callstack for each leaked instances is dumped to 46 // the error log. 47 // 48 // If ENABLE_LEAK_TRACKER is not defined, then the check has no effect. 49 50 namespace base { 51 namespace debug { 52 53 #ifndef ENABLE_LEAK_TRACKER 54 55 // If leak tracking is disabled, do nothing. 56 template<typename T> 57 class LeakTracker { 58 public: 59 // This destructor suppresses warnings about instances of this class not being 60 // used. ~LeakTracker()61 ~LeakTracker() {} CheckForLeaks()62 static void CheckForLeaks() {} NumLiveInstances()63 static int NumLiveInstances() { return -1; } 64 }; 65 66 #else 67 68 // If leak tracking is enabled we track where the object was allocated from. 69 70 template<typename T> 71 class LeakTracker : public LinkNode<LeakTracker<T> > { 72 public: 73 LeakTracker() { 74 instances()->Append(this); 75 } 76 77 ~LeakTracker() { 78 this->RemoveFromList(); 79 } 80 81 static void CheckForLeaks() { 82 // Walk the allocation list and print each entry it contains. 83 size_t count = 0; 84 85 // Copy the first 3 leak allocation callstacks onto the stack. 86 // This way if we hit the CHECK() in a release build, the leak 87 // information will be available in mini-dump. 88 const size_t kMaxStackTracesToCopyOntoStack = 3; 89 StackTrace stacktraces[kMaxStackTracesToCopyOntoStack]; 90 91 for (LinkNode<LeakTracker<T> >* node = instances()->head(); 92 node != instances()->end(); 93 node = node->next()) { 94 StackTrace& allocation_stack = node->value()->allocation_stack_; 95 96 if (count < kMaxStackTracesToCopyOntoStack) 97 stacktraces[count] = allocation_stack; 98 99 ++count; 100 if (LOG_IS_ON(ERROR)) { 101 LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:"; 102 allocation_stack.OutputToStream(&LOG_STREAM(ERROR)); 103 } 104 } 105 106 CHECK_EQ(0u, count); 107 108 // Hack to keep |stacktraces| and |count| alive (so compiler 109 // doesn't optimize it out, and it will appear in mini-dumps). 110 if (count == 0x1234) { 111 for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i) 112 stacktraces[i].Print(); 113 } 114 } 115 116 static int NumLiveInstances() { 117 // Walk the allocation list and count how many entries it has. 118 int count = 0; 119 for (LinkNode<LeakTracker<T> >* node = instances()->head(); 120 node != instances()->end(); 121 node = node->next()) { 122 ++count; 123 } 124 return count; 125 } 126 127 private: 128 // Each specialization of LeakTracker gets its own static storage. 129 static LinkedList<LeakTracker<T> >* instances() { 130 static LinkedList<LeakTracker<T> > list; 131 return &list; 132 } 133 134 StackTrace allocation_stack_; 135 }; 136 137 #endif // ENABLE_LEAK_TRACKER 138 139 } // namespace debug 140 } // namespace base 141 142 #endif // BASE_DEBUG_LEAK_TRACKER_H_ 143