count_new.hpp (12638B)
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 int aligned_new_called; 63 int aligned_delete_called; 64 std::size_t last_new_size; 65 std::size_t last_new_align; 66 std::size_t last_delete_align; 67 68 int outstanding_array_new; 69 int new_array_called; 70 int delete_array_called; 71 int aligned_new_array_called; 72 int aligned_delete_array_called; 73 std::size_t last_new_array_size; 74 std::size_t last_new_array_align; 75 std::size_t last_delete_array_align; 76 77 public: 78 void newCalled(std::size_t s) 79 { 80 assert(disable_allocations == false); 81 assert(s); 82 if (throw_after == 0) { 83 throw_after = never_throw_value; 84 detail::throw_bad_alloc_helper(); 85 } else if (throw_after != never_throw_value) { 86 --throw_after; 87 } 88 ++new_called; 89 ++outstanding_new; 90 last_new_size = s; 91 } 92 93 void alignedNewCalled(std::size_t s, std::size_t a) { 94 newCalled(s); 95 ++aligned_new_called; 96 last_new_align = a; 97 } 98 99 void deleteCalled(void * p) 100 { 101 assert(p); 102 --outstanding_new; 103 ++delete_called; 104 } 105 106 void alignedDeleteCalled(void *p, std::size_t a) { 107 deleteCalled(p); 108 ++aligned_delete_called; 109 last_delete_align = a; 110 } 111 112 void newArrayCalled(std::size_t s) 113 { 114 assert(disable_allocations == false); 115 assert(s); 116 if (throw_after == 0) { 117 throw_after = never_throw_value; 118 detail::throw_bad_alloc_helper(); 119 } else { 120 // don't decrement throw_after here. newCalled will end up doing that. 121 } 122 ++outstanding_array_new; 123 ++new_array_called; 124 last_new_array_size = s; 125 } 126 127 void alignedNewArrayCalled(std::size_t s, std::size_t a) { 128 newArrayCalled(s); 129 ++aligned_new_array_called; 130 last_new_array_align = a; 131 } 132 133 void deleteArrayCalled(void * p) 134 { 135 assert(p); 136 --outstanding_array_new; 137 ++delete_array_called; 138 } 139 140 void alignedDeleteArrayCalled(void * p, std::size_t a) { 141 deleteArrayCalled(p); 142 ++aligned_delete_array_called; 143 last_delete_array_align = a; 144 } 145 146 void disableAllocations() 147 { 148 disable_allocations = true; 149 } 150 151 void enableAllocations() 152 { 153 disable_allocations = false; 154 } 155 156 void reset() 157 { 158 disable_allocations = false; 159 throw_after = never_throw_value; 160 161 outstanding_new = 0; 162 new_called = 0; 163 delete_called = 0; 164 aligned_new_called = 0; 165 aligned_delete_called = 0; 166 last_new_size = 0; 167 last_new_align = 0; 168 169 outstanding_array_new = 0; 170 new_array_called = 0; 171 delete_array_called = 0; 172 aligned_new_array_called = 0; 173 aligned_delete_array_called = 0; 174 last_new_array_size = 0; 175 last_new_array_align = 0; 176 } 177 178 public: 179 bool checkOutstandingNewEq(int n) const 180 { 181 return disable_checking || n == outstanding_new; 182 } 183 184 bool checkOutstandingNewNotEq(int n) const 185 { 186 return disable_checking || n != outstanding_new; 187 } 188 189 bool checkNewCalledEq(int n) const 190 { 191 return disable_checking || n == new_called; 192 } 193 194 bool checkNewCalledNotEq(int n) const 195 { 196 return disable_checking || n != new_called; 197 } 198 199 bool checkNewCalledGreaterThan(int n) const 200 { 201 return disable_checking || new_called > n; 202 } 203 204 bool checkDeleteCalledEq(int n) const 205 { 206 return disable_checking || n == delete_called; 207 } 208 209 bool checkDeleteCalledNotEq(int n) const 210 { 211 return disable_checking || n != delete_called; 212 } 213 214 bool checkAlignedNewCalledEq(int n) const 215 { 216 return disable_checking || n == aligned_new_called; 217 } 218 219 bool checkAlignedNewCalledNotEq(int n) const 220 { 221 return disable_checking || n != aligned_new_called; 222 } 223 224 bool checkAlignedNewCalledGreaterThan(int n) const 225 { 226 return disable_checking || aligned_new_called > n; 227 } 228 229 bool checkAlignedDeleteCalledEq(int n) const 230 { 231 return disable_checking || n == aligned_delete_called; 232 } 233 234 bool checkAlignedDeleteCalledNotEq(int n) const 235 { 236 return disable_checking || n != aligned_delete_called; 237 } 238 239 bool checkLastNewSizeEq(std::size_t n) const 240 { 241 return disable_checking || n == last_new_size; 242 } 243 244 bool checkLastNewSizeNotEq(std::size_t n) const 245 { 246 return disable_checking || n != last_new_size; 247 } 248 249 bool checkLastNewAlignEq(std::size_t n) const 250 { 251 return disable_checking || n == last_new_align; 252 } 253 254 bool checkLastNewAlignNotEq(std::size_t n) const 255 { 256 return disable_checking || n != last_new_align; 257 } 258 259 bool checkLastDeleteAlignEq(std::size_t n) const 260 { 261 return disable_checking || n == last_delete_align; 262 } 263 264 bool checkLastDeleteAlignNotEq(std::size_t n) const 265 { 266 return disable_checking || n != last_delete_align; 267 } 268 269 bool checkOutstandingArrayNewEq(int n) const 270 { 271 return disable_checking || n == outstanding_array_new; 272 } 273 274 bool checkOutstandingArrayNewNotEq(int n) const 275 { 276 return disable_checking || n != outstanding_array_new; 277 } 278 279 bool checkNewArrayCalledEq(int n) const 280 { 281 return disable_checking || n == new_array_called; 282 } 283 284 bool checkNewArrayCalledNotEq(int n) const 285 { 286 return disable_checking || n != new_array_called; 287 } 288 289 bool checkDeleteArrayCalledEq(int n) const 290 { 291 return disable_checking || n == delete_array_called; 292 } 293 294 bool checkDeleteArrayCalledNotEq(int n) const 295 { 296 return disable_checking || n != delete_array_called; 297 } 298 299 bool checkAlignedNewArrayCalledEq(int n) const 300 { 301 return disable_checking || n == aligned_new_array_called; 302 } 303 304 bool checkAlignedNewArrayCalledNotEq(int n) const 305 { 306 return disable_checking || n != aligned_new_array_called; 307 } 308 309 bool checkAlignedNewArrayCalledGreaterThan(int n) const 310 { 311 return disable_checking || aligned_new_array_called > n; 312 } 313 314 bool checkAlignedDeleteArrayCalledEq(int n) const 315 { 316 return disable_checking || n == aligned_delete_array_called; 317 } 318 319 bool checkAlignedDeleteArrayCalledNotEq(int n) const 320 { 321 return disable_checking || n != aligned_delete_array_called; 322 } 323 324 bool checkLastNewArraySizeEq(std::size_t n) const 325 { 326 return disable_checking || n == last_new_array_size; 327 } 328 329 bool checkLastNewArraySizeNotEq(std::size_t n) const 330 { 331 return disable_checking || n != last_new_array_size; 332 } 333 334 bool checkLastNewArrayAlignEq(std::size_t n) const 335 { 336 return disable_checking || n == last_new_array_align; 337 } 338 339 bool checkLastNewArrayAlignNotEq(std::size_t n) const 340 { 341 return disable_checking || n != last_new_array_align; 342 } 343 }; 344 345 #ifdef DISABLE_NEW_COUNT 346 const bool MemCounter::disable_checking = true; 347 #else 348 const bool MemCounter::disable_checking = false; 349 #endif 350 351 inline MemCounter* getGlobalMemCounter() { 352 static MemCounter counter((MemCounter::MemCounterCtorArg_())); 353 return &counter; 354 } 355 356 MemCounter &globalMemCounter = *getGlobalMemCounter(); 357 358 #ifndef DISABLE_NEW_COUNT 359 void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc) 360 { 361 getGlobalMemCounter()->newCalled(s); 362 void* ret = std::malloc(s); 363 if (ret == nullptr) 364 detail::throw_bad_alloc_helper(); 365 return ret; 366 } 367 368 void operator delete(void* p) TEST_NOEXCEPT 369 { 370 getGlobalMemCounter()->deleteCalled(p); 371 std::free(p); 372 } 373 374 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc) 375 { 376 getGlobalMemCounter()->newArrayCalled(s); 377 return operator new(s); 378 } 379 380 void operator delete[](void* p) TEST_NOEXCEPT 381 { 382 getGlobalMemCounter()->deleteArrayCalled(p); 383 operator delete(p); 384 } 385 386 #ifndef TEST_HAS_NO_ALIGNED_ALLOCATION 387 #if defined(_LIBCPP_MSVCRT_LIKE) || \ 388 (!defined(_LIBCPP_VERSION) && defined(_WIN32)) 389 #define USE_ALIGNED_ALLOC 390 #endif 391 392 void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { 393 const std::size_t a = static_cast<std::size_t>(av); 394 getGlobalMemCounter()->alignedNewCalled(s, a); 395 void *ret; 396 #ifdef USE_ALIGNED_ALLOC 397 ret = _aligned_malloc(s, a); 398 #else 399 posix_memalign(&ret, a, s); 400 #endif 401 if (ret == nullptr) 402 detail::throw_bad_alloc_helper(); 403 return ret; 404 } 405 406 void operator delete(void *p, std::align_val_t av) TEST_NOEXCEPT { 407 const std::size_t a = static_cast<std::size_t>(av); 408 getGlobalMemCounter()->alignedDeleteCalled(p, a); 409 if (p) { 410 #ifdef USE_ALIGNED_ALLOC 411 ::_aligned_free(p); 412 #else 413 ::free(p); 414 #endif 415 } 416 } 417 418 void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { 419 const std::size_t a = static_cast<std::size_t>(av); 420 getGlobalMemCounter()->alignedNewArrayCalled(s, a); 421 return operator new(s, av); 422 } 423 424 void operator delete[](void *p, std::align_val_t av) TEST_NOEXCEPT { 425 const std::size_t a = static_cast<std::size_t>(av); 426 getGlobalMemCounter()->alignedDeleteArrayCalled(p, a); 427 return operator delete(p, av); 428 } 429 430 #endif // TEST_HAS_NO_ALIGNED_ALLOCATION 431 432 #endif // DISABLE_NEW_COUNT 433 434 struct DisableAllocationGuard { 435 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) 436 { 437 // Don't re-disable if already disabled. 438 if (globalMemCounter.disable_allocations == true) m_disabled = false; 439 if (m_disabled) globalMemCounter.disableAllocations(); 440 } 441 442 void release() { 443 if (m_disabled) globalMemCounter.enableAllocations(); 444 m_disabled = false; 445 } 446 447 ~DisableAllocationGuard() { 448 release(); 449 } 450 451 private: 452 bool m_disabled; 453 454 DisableAllocationGuard(DisableAllocationGuard const&); 455 DisableAllocationGuard& operator=(DisableAllocationGuard const&); 456 }; 457 458 struct RequireAllocationGuard { 459 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) 460 : m_req_alloc(RequireAtLeast), 461 m_new_count_on_init(globalMemCounter.new_called), 462 m_outstanding_new_on_init(globalMemCounter.outstanding_new), 463 m_exactly(false) 464 { 465 } 466 467 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; } 468 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; } 469 470 ~RequireAllocationGuard() { 471 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init))); 472 std::size_t Expect = m_new_count_on_init + m_req_alloc; 473 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) || 474 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect)))); 475 } 476 477 private: 478 std::size_t m_req_alloc; 479 const std::size_t m_new_count_on_init; 480 const std::size_t m_outstanding_new_on_init; 481 bool m_exactly; 482 RequireAllocationGuard(RequireAllocationGuard const&); 483 RequireAllocationGuard& operator=(RequireAllocationGuard const&); 484 }; 485 486 #endif /* COUNT_NEW_HPP */