• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CheckForLeaks()56   static void CheckForLeaks() {}
NumLiveInstances()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