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