summaryrefslogtreecommitdiffstats
path: root/base/debug/leak_tracker.h
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-26 04:07:50 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-26 04:07:50 +0000
commit58580359a452cb7c3b9580edc0843c3ab3d158df (patch)
tree964dbcc1505f4b9c2bbb5e7a64720861d604c8f3 /base/debug/leak_tracker.h
parent23872906817de5d402b0c2da6d5f7ee6026378e6 (diff)
downloadchromium_src-58580359a452cb7c3b9580edc0843c3ab3d158df.zip
chromium_src-58580359a452cb7c3b9580edc0843c3ab3d158df.tar.gz
chromium_src-58580359a452cb7c3b9580edc0843c3ab3d158df.tar.bz2
Move debug-related stuff from base to the base/debug directory and use the
base::debug namespace. This splits apart debug_util into base/debugger and base/stack_trace There are still two functions in debug_util that I'm not sure what to do with. Since this uses the base::debug namespace, I removed the functions in debugger.h from the static class and just made them free functions in the namespace. TEST=it compiles BUG=none Review URL: http://codereview.chromium.org/3945002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63859 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/debug/leak_tracker.h')
-rw-r--r--base/debug/leak_tracker.h134
1 files changed, 134 insertions, 0 deletions
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
new file mode 100644
index 0000000..8af82a9
--- /dev/null
+++ b/base/debug/leak_tracker.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_LEAK_TRACKER_H_
+#define BASE_DEBUG_LEAK_TRACKER_H_
+#pragma once
+
+// Only enable leak tracking in debug builds.
+#ifndef NDEBUG
+#define ENABLE_LEAK_TRACKER
+#endif
+
+#ifdef ENABLE_LEAK_TRACKER
+#include "base/debug/stack_trace.h"
+#include "base/linked_list.h"
+#include "base/logging.h"
+#endif // ENABLE_LEAK_TRACKER
+
+// LeakTracker is a helper to verify that all instances of a class
+// have been destroyed.
+//
+// It is particularly useful for classes that are bound to a single thread --
+// before destroying that thread, one can check that there are no remaining
+// instances of that class.
+//
+// For example, to enable leak tracking for class URLRequest, start by
+// adding a member variable of type LeakTracker<URLRequest>.
+//
+// class URLRequest {
+// ...
+// private:
+// base::LeakTracker<URLRequest> leak_tracker_;
+// };
+//
+//
+// Next, when we believe all instances of URLRequest have been deleted:
+//
+// LeakTracker<URLRequest>::CheckForLeaks();
+//
+// Should the check fail (because there are live instances of URLRequest),
+// then the allocation callstack for each leaked instances is dumped to
+// the error log.
+//
+// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
+
+namespace base {
+namespace debug {
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, do nothing.
+template<typename T>
+class LeakTracker {
+ public:
+ static void CheckForLeaks() {}
+ static int NumLiveInstances() { return -1; }
+};
+
+#else
+
+// If leak tracking is enabled we track where the object was allocated from.
+
+template<typename T>
+class LeakTracker : public LinkNode<LeakTracker<T> > {
+ public:
+ LeakTracker() {
+ instances()->Append(this);
+ }
+
+ ~LeakTracker() {
+ this->RemoveFromList();
+ }
+
+ static void CheckForLeaks() {
+ // Walk the allocation list and print each entry it contains.
+ size_t count = 0;
+
+ // Copy the first 3 leak allocation callstacks onto the stack.
+ // This way if we hit the CHECK() in a release build, the leak
+ // information will be available in mini-dump.
+ const size_t kMaxStackTracesToCopyOntoStack = 3;
+ StackTrace stacktraces[kMaxStackTracesToCopyOntoStack];
+
+ for (LinkNode<LeakTracker<T> >* node = instances()->head();
+ node != instances()->end();
+ node = node->next()) {
+ StackTrace& allocation_stack = node->value()->allocation_stack_;
+
+ if (count < kMaxStackTracesToCopyOntoStack)
+ stacktraces[count] = allocation_stack;
+
+ ++count;
+ LOG(ERROR) << "Leaked " << node << " which was allocated by:";
+ allocation_stack.OutputToStream(&LOG_STREAM(ERROR));
+ }
+
+ CHECK_EQ(0u, count);
+
+ // Hack to keep |stacktraces| and |count| alive (so compiler
+ // doesn't optimize it out, and it will appear in mini-dumps).
+ if (count == 0x1234) {
+ for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i)
+ stacktraces[i].PrintBacktrace();
+ }
+ }
+
+ static int NumLiveInstances() {
+ // Walk the allocation list and count how many entries it has.
+ int count = 0;
+ for (LinkNode<LeakTracker<T> >* node = instances()->head();
+ node != instances()->end();
+ node = node->next()) {
+ ++count;
+ }
+ return count;
+ }
+
+ private:
+ // Each specialization of LeakTracker gets its own static storage.
+ static LinkedList<LeakTracker<T> >* instances() {
+ static LinkedList<LeakTracker<T> > list;
+ return &list;
+ }
+
+ StackTrace allocation_stack_;
+};
+
+#endif // ENABLE_LEAK_TRACKER
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_LEAK_TRACKER_H_