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