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