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