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