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