1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef COUNT_NEW_HPP 11 #define COUNT_NEW_HPP 12 13 # include <cstdlib> 14 # include <cassert> 15 # include <new> 16 17 #include "test_macros.h" 18 19 #if defined(TEST_HAS_SANITIZERS) 20 #define DISABLE_NEW_COUNT 21 #endif 22 23 namespace detail 24 { 25 TEST_NORETURN 26 inline void throw_bad_alloc_helper() { 27 #ifndef TEST_HAS_NO_EXCEPTIONS 28 throw std::bad_alloc(); 29 #else 30 std::abort(); 31 #endif 32 } 33 } 34 35 class MemCounter 36 { 37 public: 38 // Make MemCounter super hard to accidentally construct or copy. 39 class MemCounterCtorArg_ {}; 40 explicit MemCounter(MemCounterCtorArg_) { reset(); } 41 42 private: 43 MemCounter(MemCounter const &); 44 MemCounter & operator=(MemCounter const &); 45 46 public: 47 // All checks return true when disable_checking is enabled. 48 static const bool disable_checking; 49 50 // Disallow any allocations from occurring. Useful for testing that 51 // code doesn't perform any allocations. 52 bool disable_allocations; 53 54 // number of allocations to throw after. Default (unsigned)-1. If 55 // throw_after has the default value it will never be decremented. 56 static const unsigned never_throw_value = static_cast<unsigned>(-1); 57 unsigned throw_after; 58 59 int outstanding_new; 60 int new_called; 61 int delete_called; 62 std::size_t last_new_size; 63 64 int outstanding_array_new; 65 int new_array_called; 66 int delete_array_called; 67 std::size_t last_new_array_size; 68 69 public: 70 void newCalled(std::size_t s) 71 { 72 assert(disable_allocations == false); 73 assert(s); 74 if (throw_after == 0) { 75 throw_after = never_throw_value; 76 detail::throw_bad_alloc_helper(); 77 } else if (throw_after != never_throw_value) { 78 --throw_after; 79 } 80 ++new_called; 81 ++outstanding_new; 82 last_new_size = s; 83 } 84 85 void deleteCalled(void * p) 86 { 87 assert(p); 88 --outstanding_new; 89 ++delete_called; 90 } 91 92 void newArrayCalled(std::size_t s) 93 { 94 assert(disable_allocations == false); 95 assert(s); 96 if (throw_after == 0) { 97 throw_after = never_throw_value; 98 detail::throw_bad_alloc_helper(); 99 } else { 100 // don't decrement throw_after here. newCalled will end up doing that. 101 } 102 ++outstanding_array_new; 103 ++new_array_called; 104 last_new_array_size = s; 105 } 106 107 void deleteArrayCalled(void * p) 108 { 109 assert(p); 110 --outstanding_array_new; 111 ++delete_array_called; 112 } 113 114 void disableAllocations() 115 { 116 disable_allocations = true; 117 } 118 119 void enableAllocations() 120 { 121 disable_allocations = false; 122 } 123 124 125 void reset() 126 { 127 disable_allocations = false; 128 throw_after = never_throw_value; 129 130 outstanding_new = 0; 131 new_called = 0; 132 delete_called = 0; 133 last_new_size = 0; 134 135 outstanding_array_new = 0; 136 new_array_called = 0; 137 delete_array_called = 0; 138 last_new_array_size = 0; 139 } 140 141 public: 142 bool checkOutstandingNewEq(int n) const 143 { 144 return disable_checking || n == outstanding_new; 145 } 146 147 bool checkOutstandingNewNotEq(int n) const 148 { 149 return disable_checking || n != outstanding_new; 150 } 151 152 bool checkNewCalledEq(int n) const 153 { 154 return disable_checking || n == new_called; 155 } 156 157 bool checkNewCalledNotEq(int n) const 158 { 159 return disable_checking || n != new_called; 160 } 161 162 bool checkNewCalledGreaterThan(int n) const 163 { 164 return disable_checking || new_called > n; 165 } 166 167 bool checkDeleteCalledEq(int n) const 168 { 169 return disable_checking || n == delete_called; 170 } 171 172 bool checkDeleteCalledNotEq(int n) const 173 { 174 return disable_checking || n != delete_called; 175 } 176 177 bool checkLastNewSizeEq(std::size_t n) const 178 { 179 return disable_checking || n == last_new_size; 180 } 181 182 bool checkLastNewSizeNotEq(std::size_t n) const 183 { 184 return disable_checking || n != last_new_size; 185 } 186 187 bool checkOutstandingArrayNewEq(int n) const 188 { 189 return disable_checking || n == outstanding_array_new; 190 } 191 192 bool checkOutstandingArrayNewNotEq(int n) const 193 { 194 return disable_checking || n != outstanding_array_new; 195 } 196 197 bool checkNewArrayCalledEq(int n) const 198 { 199 return disable_checking || n == new_array_called; 200 } 201 202 bool checkNewArrayCalledNotEq(int n) const 203 { 204 return disable_checking || n != new_array_called; 205 } 206 207 bool checkDeleteArrayCalledEq(int n) const 208 { 209 return disable_checking || n == delete_array_called; 210 } 211 212 bool checkDeleteArrayCalledNotEq(int n) const 213 { 214 return disable_checking || n != delete_array_called; 215 } 216 217 bool checkLastNewArraySizeEq(std::size_t n) const 218 { 219 return disable_checking || n == last_new_array_size; 220 } 221 222 bool checkLastNewArraySizeNotEq(std::size_t n) const 223 { 224 return disable_checking || n != last_new_array_size; 225 } 226 }; 227 228 #ifdef DISABLE_NEW_COUNT 229 const bool MemCounter::disable_checking = true; 230 #else 231 const bool MemCounter::disable_checking = false; 232 #endif 233 234 MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_())); 235 236 #ifndef DISABLE_NEW_COUNT 237 void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc) 238 { 239 globalMemCounter.newCalled(s); 240 void* ret = std::malloc(s); 241 if (ret == nullptr) 242 detail::throw_bad_alloc_helper(); 243 return ret; 244 } 245 246 void operator delete(void* p) TEST_NOEXCEPT 247 { 248 globalMemCounter.deleteCalled(p); 249 std::free(p); 250 } 251 252 253 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc) 254 { 255 globalMemCounter.newArrayCalled(s); 256 return operator new(s); 257 } 258 259 260 void operator delete[](void* p) TEST_NOEXCEPT 261 { 262 globalMemCounter.deleteArrayCalled(p); 263 operator delete(p); 264 } 265 266 #endif // DISABLE_NEW_COUNT 267 268 269 struct DisableAllocationGuard { 270 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) 271 { 272 // Don't re-disable if already disabled. 273 if (globalMemCounter.disable_allocations == true) m_disabled = false; 274 if (m_disabled) globalMemCounter.disableAllocations(); 275 } 276 277 void release() { 278 if (m_disabled) globalMemCounter.enableAllocations(); 279 m_disabled = false; 280 } 281 282 ~DisableAllocationGuard() { 283 release(); 284 } 285 286 private: 287 bool m_disabled; 288 289 DisableAllocationGuard(DisableAllocationGuard const&); 290 DisableAllocationGuard& operator=(DisableAllocationGuard const&); 291 }; 292 293 294 struct RequireAllocationGuard { 295 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) 296 : m_req_alloc(RequireAtLeast), 297 m_new_count_on_init(globalMemCounter.new_called), 298 m_outstanding_new_on_init(globalMemCounter.outstanding_new), 299 m_exactly(false) 300 { 301 } 302 303 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; } 304 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; } 305 306 ~RequireAllocationGuard() { 307 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init))); 308 std::size_t Expect = m_new_count_on_init + m_req_alloc; 309 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) || 310 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect)))); 311 } 312 313 private: 314 std::size_t m_req_alloc; 315 const std::size_t m_new_count_on_init; 316 const std::size_t m_outstanding_new_on_init; 317 bool m_exactly; 318 RequireAllocationGuard(RequireAllocationGuard const&); 319 RequireAllocationGuard& operator=(RequireAllocationGuard const&); 320 }; 321 322 #endif /* COUNT_NEW_HPP */ 323