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