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