Home | History | Annotate | Download | only in base
      1 // 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 
      8 // Only enable leak tracking in debug builds.
      9 #ifndef NDEBUG
     10 #define ENABLE_LEAK_TRACKER
     11 #endif
     12 
     13 #ifdef ENABLE_LEAK_TRACKER
     14 #include "base/debug_util.h"
     15 #include "base/linked_list.h"
     16 #include "base/logging.h"
     17 #endif  // ENABLE_LEAK_TRACKER
     18 
     19 // LeakTracker is a helper to verify that all instances of a class
     20 // 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 //
     44 // If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
     45 
     46 namespace base {
     47 
     48 #ifndef ENABLE_LEAK_TRACKER
     49 
     50 // If leak tracking is disabled, do nothing.
     51 template<typename T>
     52 class LeakTracker {
     53  public:
     54   static void CheckForLeaks() {}
     55   static int NumLiveInstances() { return -1; }
     56 };
     57 
     58 #else
     59 
     60 // If leak tracking is enabled we track where the object was allocated from.
     61 
     62 template<typename T>
     63 class 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.
     75     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 
     83     for (LinkNode<LeakTracker<T> >* node = instances()->head();
     84          node != instances()->end();
     85          node = node->next()) {
     86       StackTrace& allocation_stack = node->value()->allocation_stack_;
     87 
     88       if (count < kMaxStackTracesToCopyOntoStack)
     89         stacktraces[count] = allocation_stack;
     90 
     91       ++count;
     92       LOG(ERROR) << "Leaked " << node << " which was allocated by:";
     93       allocation_stack.OutputToStream(&LOG(ERROR));
     94     }
     95 
     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     }
    104   }
    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 
    127 #endif  // ENABLE_LEAK_TRACKER
    128 
    129 }  // namespace base
    130 
    131 #endif  // BASE_LEAK_TRACKER_H_
    132