diff options
author | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-11 21:38:54 +0000 |
---|---|---|
committer | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-11 21:38:54 +0000 |
commit | 48ca901238509dd4c5f7bb30c66ef36f5dafc828 (patch) | |
tree | 34a2d3976009fd351aa91e9257dd6522907928dd /base/leak_tracker.h | |
parent | 51e9e931b1d9c36605c6336a3002fda22f023b36 (diff) | |
download | chromium_src-48ca901238509dd4c5f7bb30c66ef36f5dafc828.zip chromium_src-48ca901238509dd4c5f7bb30c66ef36f5dafc828.tar.gz chromium_src-48ca901238509dd4c5f7bb30c66ef36f5dafc828.tar.bz2 |
Add checks to DEBUG mode that no instance of URLRequest or URLFetcher survives the destruction of the IO thread.
This checking is done by introducing a new helper class to base called LeakTracker. Classes that you want to check for leaks just need to extend LeakTracker.
The reason I am picking on URLFetcher / URLRequest, is I believe we have a bug that is making an instance of URLFetcher to outlive the IO thread.
This causes various sorts of badness.
For example:
If URLFetcher survives the IO thread, then URLRequestContext remains referenced and therefore also survives IO thread. In turn HostResolverImpl survives the IO thread, so any outstanding resolve requests are NOT cancelled before the IO thread is decomissioned. So now, when the worker thread doing the DNS resolve finally finishes (assuming it finishes before the rogue URLRequest is destroyed), it post the result to a defunct message loop. KAB00m! (http://crbug.com/15513)
Moreover, I believe we hit this same problem sporadically in AutomationProxyTest.AutocompleteGetSetText -- the test is flaky on the buildbots, and I've seen DCHECKs which suggest it is related to this issue.
BUG=http://crbug.com/18372
Review URL: http://codereview.chromium.org/160447
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23084 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/leak_tracker.h')
-rw-r--r-- | base/leak_tracker.h | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/base/leak_tracker.h b/base/leak_tracker.h new file mode 100644 index 0000000..d289691e --- /dev/null +++ b/base/leak_tracker.h @@ -0,0 +1,106 @@ +// Copyright (c) 2009 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_LEAK_TRACKER_H_ +#define BASE_LEAK_TRACKER_H_ + +#ifndef NDEBUG +#include "base/debug_util.h" +#include "base/linked_list.h" +#include "base/logging.h" +#endif + +// LeakTracker is a debug 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. +// +// In RELEASE mode the check has no effect. + +namespace base { + +#ifdef NDEBUG + +// In release mode we do nothing. +template<typename T> +class LeakTracker { + public: + static void CheckForLeaks() {} + static int NumLiveInstances() { return -1; } +}; + +#else + +// In debug mode 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. + int count = 0; + for (LinkNode<LeakTracker<T> >* node = instances()->head(); + node != instances()->end(); + node = node->next()) { + ++count; + LOG(ERROR) << "Leaked " << node << " which was allocated by:"; + node->value()->allocation_stack_.PrintBacktrace(); + } + DCHECK_EQ(0, count); + } + + 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 // NDEBUG + +} // namespace base + +#endif // BASE_LEAK_TRACKER_H_ |