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: ~LeakTracker()59 ~LeakTracker() {} CheckForLeaks()60 static void CheckForLeaks() {} NumLiveInstances()61 static int NumLiveInstances() { return -1; } 62 }; 63 64 #else 65 66 // If leak tracking is enabled we track where the object was allocated from. 67 68 template<typename T> 69 class LeakTracker : public LinkNode<LeakTracker<T> > { 70 public: 71 LeakTracker() { 72 instances()->Append(this); 73 } 74 75 ~LeakTracker() { 76 this->RemoveFromList(); 77 } 78 79 static void CheckForLeaks() { 80 // Walk the allocation list and print each entry it contains. 81 size_t count = 0; 82 83 // Copy the first 3 leak allocation callstacks onto the stack. 84 // This way if we hit the CHECK() in a release build, the leak 85 // information will be available in mini-dump. 86 const size_t kMaxStackTracesToCopyOntoStack = 3; 87 StackTrace stacktraces[kMaxStackTracesToCopyOntoStack]; 88 89 for (LinkNode<LeakTracker<T> >* node = instances()->head(); 90 node != instances()->end(); 91 node = node->next()) { 92 StackTrace& allocation_stack = node->value()->allocation_stack_; 93 94 if (count < kMaxStackTracesToCopyOntoStack) 95 stacktraces[count] = allocation_stack; 96 97 ++count; 98 if (LOG_IS_ON(ERROR)) { 99 LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:"; 100 allocation_stack.OutputToStream(&LOG_STREAM(ERROR)); 101 } 102 } 103 104 CHECK_EQ(0u, count); 105 106 // Hack to keep |stacktraces| and |count| alive (so compiler 107 // doesn't optimize it out, and it will appear in mini-dumps). 108 if (count == 0x1234) { 109 for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i) 110 stacktraces[i].Print(); 111 } 112 } 113 114 static int NumLiveInstances() { 115 // Walk the allocation list and count how many entries it has. 116 int count = 0; 117 for (LinkNode<LeakTracker<T> >* node = instances()->head(); 118 node != instances()->end(); 119 node = node->next()) { 120 ++count; 121 } 122 return count; 123 } 124 125 private: 126 // Each specialization of LeakTracker gets its own static storage. 127 static LinkedList<LeakTracker<T> >* instances() { 128 static LinkedList<LeakTracker<T> > list; 129 return &list; 130 } 131 132 StackTrace allocation_stack_; 133 }; 134 135 #endif // ENABLE_LEAK_TRACKER 136 137 } // namespace debug 138 } // namespace base 139 140 #endif // BASE_DEBUG_LEAK_TRACKER_H_ 141