| // Copyright (c) 2012 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_ | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include "build_config.h" | 
 |  | 
 | // Only enable leak tracking in non-uClibc debug builds. | 
 | #if !defined(NDEBUG) && !defined(__UCLIBC__) | 
 | #define ENABLE_LEAK_TRACKER | 
 | #endif | 
 |  | 
 | #ifdef ENABLE_LEAK_TRACKER | 
 | #include "base/containers/linked_list.h" | 
 | #include "base/debug/stack_trace.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 net::URLRequest, start by | 
 | // adding a member variable of type LeakTracker<net::URLRequest>. | 
 | // | 
 | //   class URLRequest { | 
 | //     ... | 
 | //    private: | 
 | //     base::LeakTracker<URLRequest> leak_tracker_; | 
 | //   }; | 
 | // | 
 | // | 
 | // Next, when we believe all instances of net::URLRequest have been deleted: | 
 | // | 
 | //   LeakTracker<net::URLRequest>::CheckForLeaks(); | 
 | // | 
 | // Should the check fail (because there are live instances of net::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: | 
 |   // This destructor suppresses warnings about instances of this class not being | 
 |   // used. | 
 |   ~LeakTracker() {} | 
 |   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; | 
 |       if (LOG_IS_ON(ERROR)) { | 
 |         LOG_STREAM(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].Print(); | 
 |     } | 
 |   } | 
 |  | 
 |   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_ |