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