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 47namespace base { 48namespace debug { 49 50#ifndef ENABLE_LEAK_TRACKER 51 52// If leak tracking is disabled, do nothing. 53template<typename T> 54class 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 64template<typename T> 65class 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