blob: de6ff293fd921841333410cb577c4e92dd08fdff [file] [log] [blame]
ericroman@google.com7e41f132009-08-12 06:38:54 +09001// Copyright (c) 2009 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_LEAK_TRACKER_H_
6#define BASE_LEAK_TRACKER_H_
7
eroman@chromium.org76b91eb2009-09-30 11:42:13 +09008// Only enable leak tracking in debug builds.
9#ifndef NDEBUG
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090010#define ENABLE_LEAK_TRACKER
11#endif
12
13#ifdef ENABLE_LEAK_TRACKER
ericroman@google.com7e41f132009-08-12 06:38:54 +090014#include "base/debug_util.h"
15#include "base/linked_list.h"
16#include "base/logging.h"
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090017#endif // ENABLE_LEAK_TRACKER
ericroman@google.com7e41f132009-08-12 06:38:54 +090018
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090019// LeakTracker is a helper to verify that all instances of a class
ericroman@google.com7e41f132009-08-12 06:38:54 +090020// have been destroyed.
21//
22// It is particularly useful for classes that are bound to a single thread --
23// before destroying that thread, one can check that there are no remaining
24// instances of that class.
25//
26// For example, to enable leak tracking for class URLRequest, start by
27// adding a member variable of type LeakTracker<URLRequest>.
28//
29// class URLRequest {
30// ...
31// private:
32// base::LeakTracker<URLRequest> leak_tracker_;
33// };
34//
35//
36// Next, when we believe all instances of URLRequest have been deleted:
37//
38// LeakTracker<URLRequest>::CheckForLeaks();
39//
40// Should the check fail (because there are live instances of URLRequest),
41// then the allocation callstack for each leaked instances is dumped to
42// the error log.
43//
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090044// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
ericroman@google.com7e41f132009-08-12 06:38:54 +090045
46namespace base {
47
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090048#ifndef ENABLE_LEAK_TRACKER
ericroman@google.com7e41f132009-08-12 06:38:54 +090049
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090050// If leak tracking is disabled, do nothing.
ericroman@google.com7e41f132009-08-12 06:38:54 +090051template<typename T>
52class LeakTracker {
53 public:
54 static void CheckForLeaks() {}
55 static int NumLiveInstances() { return -1; }
56};
57
58#else
59
eroman@chromium.orgb0a25412009-09-17 06:14:08 +090060// If leak tracking is enabled we track where the object was allocated from.
ericroman@google.com7e41f132009-08-12 06:38:54 +090061
62template<typename T>
63class LeakTracker : public LinkNode<LeakTracker<T> > {
64 public:
65 LeakTracker() {
66 instances()->Append(this);
67 }
68
69 ~LeakTracker() {
70 this->RemoveFromList();
71 }
72
73 static void CheckForLeaks() {
74 // Walk the allocation list and print each entry it contains.
eroman@chromium.orgbc13fa72009-09-22 04:44:54 +090075 size_t count = 0;
76
77 // Copy the first 3 leak allocation callstacks onto the stack.
78 // This way if we hit the CHECK() in a release build, the leak
79 // information will be available in mini-dump.
80 const size_t kMaxStackTracesToCopyOntoStack = 3;
81 StackTrace stacktraces[kMaxStackTracesToCopyOntoStack];
82
ericroman@google.com7e41f132009-08-12 06:38:54 +090083 for (LinkNode<LeakTracker<T> >* node = instances()->head();
84 node != instances()->end();
85 node = node->next()) {
eroman@chromium.orgbc13fa72009-09-22 04:44:54 +090086 StackTrace& allocation_stack = node->value()->allocation_stack_;
87
88 if (count < kMaxStackTracesToCopyOntoStack)
89 stacktraces[count] = allocation_stack;
90
ericroman@google.com7e41f132009-08-12 06:38:54 +090091 ++count;
92 LOG(ERROR) << "Leaked " << node << " which was allocated by:";
eroman@chromium.orgbc13fa72009-09-22 04:44:54 +090093 allocation_stack.PrintBacktrace();
ericroman@google.com7e41f132009-08-12 06:38:54 +090094 }
eroman@chromium.orgbc13fa72009-09-22 04:44:54 +090095
96 CHECK(0u == count);
97
98 // Hack to keep |stacktraces| and |count| alive (so compiler
99 // doesn't optimize it out, and it will appear in mini-dumps).
100 if (count == 0x1234) {
101 for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i)
102 stacktraces[i].PrintBacktrace();
103 }
ericroman@google.com7e41f132009-08-12 06:38:54 +0900104 }
105
106 static int NumLiveInstances() {
107 // Walk the allocation list and count how many entries it has.
108 int count = 0;
109 for (LinkNode<LeakTracker<T> >* node = instances()->head();
110 node != instances()->end();
111 node = node->next()) {
112 ++count;
113 }
114 return count;
115 }
116
117 private:
118 // Each specialization of LeakTracker gets its own static storage.
119 static LinkedList<LeakTracker<T> >* instances() {
120 static LinkedList<LeakTracker<T> > list;
121 return &list;
122 }
123
124 StackTrace allocation_stack_;
125};
126
eroman@chromium.orgb0a25412009-09-17 06:14:08 +0900127#endif // ENABLE_LEAK_TRACKER
ericroman@google.com7e41f132009-08-12 06:38:54 +0900128
129} // namespace base
130
131#endif // BASE_LEAK_TRACKER_H_