Home | History | Annotate | Download | only in support
      1 #ifndef COUNT_NEW_HPP
      2 #define COUNT_NEW_HPP
      3 
      4 # include <cstdlib>
      5 # include <cassert>
      6 # include <new>
      7 
      8 #ifndef __has_feature
      9 #  define __has_feature(x) 0
     10 #endif
     11 
     12 #if  __has_feature(address_sanitizer) \
     13   || __has_feature(memory_sanitizer) \
     14   || __has_feature(thread_sanitizer)
     15 #define DISABLE_NEW_COUNT
     16 #endif
     17 
     18 class MemCounter
     19 {
     20 public:
     21     // Make MemCounter super hard to accidentally construct or copy.
     22     class MemCounterCtorArg_ {};
     23     explicit MemCounter(MemCounterCtorArg_) { reset(); }
     24 
     25 private:
     26     MemCounter(MemCounter const &);
     27     MemCounter & operator=(MemCounter const &);
     28 
     29 public:
     30     // All checks return true when disable_checking is enabled.
     31     static const bool disable_checking;
     32 
     33     // Disallow any allocations from occurring. Useful for testing that
     34     // code doesn't perform any allocations.
     35     bool disable_allocations;
     36 
     37     int outstanding_new;
     38     int new_called;
     39     int delete_called;
     40     int last_new_size;
     41 
     42     int outstanding_array_new;
     43     int new_array_called;
     44     int delete_array_called;
     45     int last_new_array_size;
     46 
     47 public:
     48     void newCalled(std::size_t s)
     49     {
     50         assert(disable_allocations == false);
     51         assert(s);
     52         ++new_called;
     53         ++outstanding_new;
     54         last_new_size = s;
     55     }
     56 
     57     void deleteCalled(void * p)
     58     {
     59         assert(p);
     60         --outstanding_new;
     61         ++delete_called;
     62     }
     63 
     64     void newArrayCalled(std::size_t s)
     65     {
     66         assert(disable_allocations == false);
     67         assert(s);
     68         ++outstanding_array_new;
     69         ++new_array_called;
     70         last_new_array_size = s;
     71     }
     72 
     73     void deleteArrayCalled(void * p)
     74     {
     75         assert(p);
     76         --outstanding_array_new;
     77         ++delete_array_called;
     78     }
     79 
     80     void disableAllocations()
     81     {
     82         disable_allocations = true;
     83     }
     84 
     85     void enableAllocations()
     86     {
     87         disable_allocations = false;
     88     }
     89 
     90     void reset()
     91     {
     92         disable_allocations = false;
     93 
     94         outstanding_new = 0;
     95         new_called = 0;
     96         delete_called = 0;
     97         last_new_size = 0;
     98 
     99         outstanding_array_new = 0;
    100         new_array_called = 0;
    101         delete_array_called = 0;
    102         last_new_array_size = 0;
    103     }
    104 
    105 public:
    106     bool checkOutstandingNewEq(int n) const
    107     {
    108         return disable_checking || n == outstanding_new;
    109     }
    110 
    111     bool checkOutstandingNewNotEq(int n) const
    112     {
    113         return disable_checking || n != outstanding_new;
    114     }
    115 
    116     bool checkNewCalledEq(int n) const
    117     {
    118         return disable_checking || n == new_called;
    119     }
    120 
    121     bool checkNewCalledNotEq(int n) const
    122     {
    123         return disable_checking || n != new_called;
    124     }
    125 
    126     bool checkDeleteCalledEq(int n) const
    127     {
    128         return disable_checking || n == delete_called;
    129     }
    130 
    131     bool checkDeleteCalledNotEq(int n) const
    132     {
    133         return disable_checking || n != delete_called;
    134     }
    135 
    136     bool checkLastNewSizeEq(int n) const
    137     {
    138         return disable_checking || n == last_new_size;
    139     }
    140 
    141     bool checkLastNewSizeNotEq(int n) const
    142     {
    143         return disable_checking || n != last_new_size;
    144     }
    145 
    146     bool checkOutstandingArrayNewEq(int n) const
    147     {
    148         return disable_checking || n == outstanding_array_new;
    149     }
    150 
    151     bool checkOutstandingArrayNewNotEq(int n) const
    152     {
    153         return disable_checking || n != outstanding_array_new;
    154     }
    155 
    156     bool checkNewArrayCalledEq(int n) const
    157     {
    158         return disable_checking || n == new_array_called;
    159     }
    160 
    161     bool checkNewArrayCalledNotEq(int n) const
    162     {
    163         return disable_checking || n != new_array_called;
    164     }
    165 
    166     bool checkDeleteArrayCalledEq(int n) const
    167     {
    168         return disable_checking || n == delete_array_called;
    169     }
    170 
    171     bool checkDeleteArrayCalledNotEq(int n) const
    172     {
    173         return disable_checking || n != delete_array_called;
    174     }
    175 
    176     bool checkLastNewArraySizeEq(int n) const
    177     {
    178         return disable_checking || n == last_new_array_size;
    179     }
    180 
    181     bool checkLastNewArraySizeNotEq(int n) const
    182     {
    183         return disable_checking || n != last_new_array_size;
    184     }
    185 };
    186 
    187 #ifdef DISABLE_NEW_COUNT
    188   const bool MemCounter::disable_checking = true;
    189 #else
    190   const bool MemCounter::disable_checking = false;
    191 #endif
    192 
    193 MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_()));
    194 
    195 #ifndef DISABLE_NEW_COUNT
    196 void* operator new(std::size_t s) throw(std::bad_alloc)
    197 {
    198     globalMemCounter.newCalled(s);
    199     return std::malloc(s);
    200 }
    201 
    202 void  operator delete(void* p) throw()
    203 {
    204     globalMemCounter.deleteCalled(p);
    205     std::free(p);
    206 }
    207 
    208 
    209 void* operator new[](std::size_t s) throw(std::bad_alloc)
    210 {
    211     globalMemCounter.newArrayCalled(s);
    212     return operator new(s);
    213 }
    214 
    215 
    216 void operator delete[](void* p) throw()
    217 {
    218     globalMemCounter.deleteArrayCalled(p);
    219     operator delete(p);
    220 }
    221 
    222 #endif // DISABLE_NEW_COUNT
    223 
    224 
    225 struct DisableAllocationGuard {
    226     explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
    227     {
    228         // Don't re-disable if already disabled.
    229         if (globalMemCounter.disable_allocations == true) m_disabled = false;
    230         if (m_disabled) globalMemCounter.disableAllocations();
    231     }
    232 
    233     void release() {
    234         if (m_disabled) globalMemCounter.enableAllocations();
    235         m_disabled = false;
    236     }
    237 
    238     ~DisableAllocationGuard() {
    239         release();
    240     }
    241 
    242 private:
    243     bool m_disabled;
    244 
    245     DisableAllocationGuard(DisableAllocationGuard const&);
    246     DisableAllocationGuard& operator=(DisableAllocationGuard const&);
    247 };
    248 
    249 #endif /* COUNT_NEW_HPP */
    250