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