1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef COUNT_NEW_H 10 #define COUNT_NEW_H 11 12 #include <algorithm> 13 #include <cassert> 14 #include <cerrno> 15 #include <cstdlib> 16 #include <new> 17 #include <type_traits> 18 19 #include "test_macros.h" 20 21 #if defined(TEST_HAS_SANITIZERS) 22 #define DISABLE_NEW_COUNT 23 #endif 24 25 namespace detail 26 { 27 [[noreturn]] inline void throw_bad_alloc_helper() { 28 #ifndef TEST_HAS_NO_EXCEPTIONS 29 throw std::bad_alloc(); 30 #else 31 std::abort(); 32 #endif 33 } 34 } 35 36 class MemCounter 37 { 38 public: 39 // Make MemCounter super hard to accidentally construct or copy. 40 class MemCounterCtorArg_ {}; 41 explicit MemCounter(MemCounterCtorArg_) { reset(); } 42 43 private: 44 MemCounter(MemCounter const &); 45 MemCounter & operator=(MemCounter const &); 46 47 public: 48 // All checks return true when disable_checking is enabled. 49 static const bool disable_checking; 50 51 // Disallow any allocations from occurring. Useful for testing that 52 // code doesn't perform any allocations. 53 bool disable_allocations; 54 55 // number of allocations to throw after. Default (unsigned)-1. If 56 // throw_after has the default value it will never be decremented. 57 static const unsigned never_throw_value = static_cast<unsigned>(-1); 58 unsigned throw_after; 59 60 int outstanding_new; 61 int new_called; 62 int delete_called; 63 int aligned_new_called; 64 int aligned_delete_called; 65 std::size_t last_new_size; 66 std::size_t last_new_align; 67 std::size_t last_delete_align; 68 69 int outstanding_array_new; 70 int new_array_called; 71 int delete_array_called; 72 int aligned_new_array_called; 73 int aligned_delete_array_called; 74 std::size_t last_new_array_size; 75 std::size_t last_new_array_align; 76 std::size_t last_delete_array_align; 77 78 public: 79 void newCalled(std::size_t s) 80 { 81 assert(disable_allocations == false); 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 if (p) { 102 --outstanding_new; 103 ++delete_called; 104 } 105 } 106 107 void alignedDeleteCalled(void *p, std::size_t a) { 108 if (p) { 109 deleteCalled(p); 110 ++aligned_delete_called; 111 last_delete_align = a; 112 } 113 } 114 115 void newArrayCalled(std::size_t s) 116 { 117 assert(disable_allocations == false); 118 if (throw_after == 0) { 119 throw_after = never_throw_value; 120 detail::throw_bad_alloc_helper(); 121 } else { 122 // don't decrement throw_after here. newCalled will end up doing that. 123 } 124 ++outstanding_array_new; 125 ++new_array_called; 126 last_new_array_size = s; 127 } 128 129 void alignedNewArrayCalled(std::size_t s, std::size_t a) { 130 newArrayCalled(s); 131 ++aligned_new_array_called; 132 last_new_array_align = a; 133 } 134 135 void deleteArrayCalled(void * p) 136 { 137 assert(p); 138 --outstanding_array_new; 139 ++delete_array_called; 140 } 141 142 void alignedDeleteArrayCalled(void * p, std::size_t a) { 143 deleteArrayCalled(p); 144 ++aligned_delete_array_called; 145 last_delete_array_align = a; 146 } 147 148 void disableAllocations() 149 { 150 disable_allocations = true; 151 } 152 153 void enableAllocations() 154 { 155 disable_allocations = false; 156 } 157 158 void reset() 159 { 160 disable_allocations = false; 161 throw_after = never_throw_value; 162 163 outstanding_new = 0; 164 new_called = 0; 165 delete_called = 0; 166 aligned_new_called = 0; 167 aligned_delete_called = 0; 168 last_new_size = 0; 169 last_new_align = 0; 170 171 outstanding_array_new = 0; 172 new_array_called = 0; 173 delete_array_called = 0; 174 aligned_new_array_called = 0; 175 aligned_delete_array_called = 0; 176 last_new_array_size = 0; 177 last_new_array_align = 0; 178 } 179 180 public: 181 bool checkOutstandingNewEq(int n) const 182 { 183 return disable_checking || n == outstanding_new; 184 } 185 186 bool checkOutstandingNewLessThanOrEqual(int n) const 187 { 188 return disable_checking || outstanding_new <= n; 189 } 190 191 bool checkOutstandingNewNotEq(int n) const 192 { 193 return disable_checking || n != outstanding_new; 194 } 195 196 bool checkNewCalledEq(int n) const 197 { 198 return disable_checking || n == new_called; 199 } 200 201 bool checkNewCalledNotEq(int n) const 202 { 203 return disable_checking || n != new_called; 204 } 205 206 bool checkNewCalledGreaterThan(int n) const 207 { 208 return disable_checking || new_called > n; 209 } 210 211 bool checkDeleteCalledEq(int n) const 212 { 213 return disable_checking || n == delete_called; 214 } 215 216 bool checkDeleteCalledNotEq(int n) const 217 { 218 return disable_checking || n != delete_called; 219 } 220 221 bool checkDeleteCalledGreaterThan(int n) const 222 { 223 return disable_checking || delete_called > n; 224 } 225 226 bool checkAlignedNewCalledEq(int n) const 227 { 228 return disable_checking || n == aligned_new_called; 229 } 230 231 bool checkAlignedNewCalledNotEq(int n) const 232 { 233 return disable_checking || n != aligned_new_called; 234 } 235 236 bool checkAlignedNewCalledGreaterThan(int n) const 237 { 238 return disable_checking || aligned_new_called > n; 239 } 240 241 bool checkAlignedDeleteCalledEq(int n) const 242 { 243 return disable_checking || n == aligned_delete_called; 244 } 245 246 bool checkAlignedDeleteCalledNotEq(int n) const 247 { 248 return disable_checking || n != aligned_delete_called; 249 } 250 251 bool checkLastNewSizeEq(std::size_t n) const 252 { 253 return disable_checking || n == last_new_size; 254 } 255 256 bool checkLastNewSizeNotEq(std::size_t n) const 257 { 258 return disable_checking || n != last_new_size; 259 } 260 261 bool checkLastNewSizeGe(std::size_t n) const 262 { 263 return disable_checking || last_new_size >= n; 264 } 265 266 bool checkLastNewAlignEq(std::size_t n) const 267 { 268 return disable_checking || n == last_new_align; 269 } 270 271 bool checkLastNewAlignNotEq(std::size_t n) const 272 { 273 return disable_checking || n != last_new_align; 274 } 275 276 bool checkLastNewAlignGe(std::size_t n) const 277 { 278 return disable_checking || last_new_align >= n; 279 } 280 281 bool checkLastDeleteAlignEq(std::size_t n) const 282 { 283 return disable_checking || n == last_delete_align; 284 } 285 286 bool checkLastDeleteAlignNotEq(std::size_t n) const 287 { 288 return disable_checking || n != last_delete_align; 289 } 290 291 bool checkOutstandingArrayNewEq(int n) const 292 { 293 return disable_checking || n == outstanding_array_new; 294 } 295 296 bool checkOutstandingArrayNewNotEq(int n) const 297 { 298 return disable_checking || n != outstanding_array_new; 299 } 300 301 bool checkNewArrayCalledEq(int n) const 302 { 303 return disable_checking || n == new_array_called; 304 } 305 306 bool checkNewArrayCalledNotEq(int n) const 307 { 308 return disable_checking || n != new_array_called; 309 } 310 311 bool checkDeleteArrayCalledEq(int n) const 312 { 313 return disable_checking || n == delete_array_called; 314 } 315 316 bool checkDeleteArrayCalledNotEq(int n) const 317 { 318 return disable_checking || n != delete_array_called; 319 } 320 321 bool checkAlignedNewArrayCalledEq(int n) const 322 { 323 return disable_checking || n == aligned_new_array_called; 324 } 325 326 bool checkAlignedNewArrayCalledNotEq(int n) const 327 { 328 return disable_checking || n != aligned_new_array_called; 329 } 330 331 bool checkAlignedNewArrayCalledGreaterThan(int n) const 332 { 333 return disable_checking || aligned_new_array_called > n; 334 } 335 336 bool checkAlignedDeleteArrayCalledEq(int n) const 337 { 338 return disable_checking || n == aligned_delete_array_called; 339 } 340 341 bool checkAlignedDeleteArrayCalledNotEq(int n) const 342 { 343 return disable_checking || n != aligned_delete_array_called; 344 } 345 346 bool checkLastNewArraySizeEq(std::size_t n) const 347 { 348 return disable_checking || n == last_new_array_size; 349 } 350 351 bool checkLastNewArraySizeNotEq(std::size_t n) const 352 { 353 return disable_checking || n != last_new_array_size; 354 } 355 356 bool checkLastNewArrayAlignEq(std::size_t n) const 357 { 358 return disable_checking || n == last_new_array_align; 359 } 360 361 bool checkLastNewArrayAlignNotEq(std::size_t n) const 362 { 363 return disable_checking || n != last_new_array_align; 364 } 365 }; 366 367 #ifdef DISABLE_NEW_COUNT 368 const bool MemCounter::disable_checking = true; 369 #else 370 const bool MemCounter::disable_checking = false; 371 #endif 372 373 TEST_DIAGNOSTIC_PUSH 374 TEST_MSVC_DIAGNOSTIC_IGNORED(4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-) 375 inline MemCounter* getGlobalMemCounter() { 376 static MemCounter counter((MemCounter::MemCounterCtorArg_())); 377 return &counter; 378 } 379 TEST_DIAGNOSTIC_POP 380 381 MemCounter &globalMemCounter = *getGlobalMemCounter(); 382 383 #ifndef DISABLE_NEW_COUNT 384 // operator new(size_t[, nothrow_t]) and operator delete(size_t[, nothrow_t]) 385 void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc) { 386 getGlobalMemCounter()->newCalled(s); 387 if (s == 0) 388 ++s; 389 void* p = std::malloc(s); 390 if (p == nullptr) 391 detail::throw_bad_alloc_helper(); 392 return p; 393 } 394 395 void* operator new(std::size_t s, std::nothrow_t const&) TEST_NOEXCEPT { 396 # ifdef TEST_HAS_NO_EXCEPTIONS 397 getGlobalMemCounter()->newCalled(s); 398 # else 399 try { 400 getGlobalMemCounter()->newCalled(s); 401 } catch (std::bad_alloc const&) { 402 return nullptr; 403 } 404 # endif 405 return std::malloc(s); 406 } 407 408 void operator delete(void* p) TEST_NOEXCEPT { 409 getGlobalMemCounter()->deleteCalled(p); 410 std::free(p); 411 } 412 413 void operator delete(void* p, std::nothrow_t const&) TEST_NOEXCEPT { 414 getGlobalMemCounter()->deleteCalled(p); 415 std::free(p); 416 } 417 418 // operator new[](size_t[, nothrow_t]) and operator delete[](size_t[, nothrow_t]) 419 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc) { 420 getGlobalMemCounter()->newArrayCalled(s); 421 if (s == 0) 422 s++; 423 void* p = std::malloc(s); 424 if (p == nullptr) 425 detail::throw_bad_alloc_helper(); 426 return p; 427 } 428 429 void* operator new[](std::size_t s, std::nothrow_t const&) TEST_NOEXCEPT { 430 # ifdef TEST_HAS_NO_EXCEPTIONS 431 getGlobalMemCounter()->newArrayCalled(s); 432 # else 433 try { 434 getGlobalMemCounter()->newArrayCalled(s); 435 } catch (std::bad_alloc const&) { 436 return nullptr; 437 } 438 # endif 439 return std::malloc(s); 440 } 441 442 void operator delete[](void* p) TEST_NOEXCEPT { 443 getGlobalMemCounter()->deleteArrayCalled(p); 444 std::free(p); 445 } 446 447 void operator delete[](void* p, std::nothrow_t const&) TEST_NOEXCEPT { 448 getGlobalMemCounter()->deleteArrayCalled(p); 449 std::free(p); 450 } 451 452 # ifndef TEST_HAS_NO_ALIGNED_ALLOCATION 453 # if defined(_LIBCPP_MSVCRT_LIKE) || (!defined(_LIBCPP_VERSION) && defined(_WIN32)) 454 # define USE_ALIGNED_ALLOC 455 # endif 456 457 # if defined(__APPLE__) 458 # if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ 459 __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) 460 # define TEST_HAS_NO_C11_ALIGNED_ALLOC 461 # endif 462 # elif defined(__ANDROID__) && __ANDROID_API__ < 28 463 # define TEST_HAS_NO_C11_ALIGNED_ALLOC 464 # endif 465 466 inline void* allocate_aligned_impl(std::size_t size, std::align_val_t align) { 467 const std::size_t alignment = static_cast<std::size_t>(align); 468 void* ret = nullptr; 469 # ifdef USE_ALIGNED_ALLOC 470 ret = _aligned_malloc(size, alignment); 471 # elif TEST_STD_VER >= 17 && !defined(TEST_HAS_NO_C11_ALIGNED_ALLOC) 472 size_t rounded_size = (size + alignment - 1) & ~(alignment - 1); 473 ret = aligned_alloc(alignment, size > rounded_size ? size : rounded_size); 474 # else 475 assert(posix_memalign(&ret, std::max(alignment, sizeof(void*)), size) != EINVAL); 476 # endif 477 return ret; 478 } 479 480 inline void free_aligned_impl(void* ptr, std::align_val_t) { 481 if (ptr) { 482 # ifdef USE_ALIGNED_ALLOC 483 ::_aligned_free(ptr); 484 # else 485 ::free(ptr); 486 # endif 487 } 488 } 489 490 // operator new(size_t, align_val_t[, nothrow_t]) and operator delete(size_t, align_val_t[, nothrow_t]) 491 void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { 492 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av)); 493 void* p = allocate_aligned_impl(s, av); 494 if (p == nullptr) 495 detail::throw_bad_alloc_helper(); 496 return p; 497 } 498 499 void* operator new(std::size_t s, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 500 # ifdef TEST_HAS_NO_EXCEPTIONS 501 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av)); 502 # else 503 try { 504 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av)); 505 } catch (std::bad_alloc const&) { 506 return nullptr; 507 } 508 # endif 509 return allocate_aligned_impl(s, av); 510 } 511 512 void operator delete(void* p, std::align_val_t av) TEST_NOEXCEPT { 513 getGlobalMemCounter()->alignedDeleteCalled(p, static_cast<std::size_t>(av)); 514 free_aligned_impl(p, av); 515 } 516 517 void operator delete(void* p, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 518 getGlobalMemCounter()->alignedDeleteCalled(p, static_cast<std::size_t>(av)); 519 free_aligned_impl(p, av); 520 } 521 522 // operator new[](size_t, align_val_t[, nothrow_t]) and operator delete[](size_t, align_val_t[, nothrow_t]) 523 void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { 524 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av)); 525 void* p = allocate_aligned_impl(s, av); 526 if (p == nullptr) 527 detail::throw_bad_alloc_helper(); 528 return p; 529 } 530 531 void* operator new[](std::size_t s, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 532 # ifdef TEST_HAS_NO_EXCEPTIONS 533 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av)); 534 # else 535 try { 536 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av)); 537 } catch (std::bad_alloc const&) { 538 return nullptr; 539 } 540 # endif 541 return allocate_aligned_impl(s, av); 542 } 543 544 void operator delete[](void* p, std::align_val_t av) TEST_NOEXCEPT { 545 getGlobalMemCounter()->alignedDeleteArrayCalled(p, static_cast<std::size_t>(av)); 546 free_aligned_impl(p, av); 547 } 548 549 void operator delete[](void* p, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 550 getGlobalMemCounter()->alignedDeleteArrayCalled(p, static_cast<std::size_t>(av)); 551 free_aligned_impl(p, av); 552 } 553 554 # endif // TEST_HAS_NO_ALIGNED_ALLOCATION 555 556 #endif // DISABLE_NEW_COUNT 557 558 struct DisableAllocationGuard { 559 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) 560 { 561 // Don't re-disable if already disabled. 562 if (globalMemCounter.disable_allocations == true) m_disabled = false; 563 if (m_disabled) globalMemCounter.disableAllocations(); 564 } 565 566 void release() { 567 if (m_disabled) globalMemCounter.enableAllocations(); 568 m_disabled = false; 569 } 570 571 ~DisableAllocationGuard() { 572 release(); 573 } 574 575 private: 576 bool m_disabled; 577 578 DisableAllocationGuard(DisableAllocationGuard const&); 579 DisableAllocationGuard& operator=(DisableAllocationGuard const&); 580 }; 581 582 #if TEST_STD_VER >= 20 583 584 struct ConstexprDisableAllocationGuard { 585 TEST_CONSTEXPR_CXX14 explicit ConstexprDisableAllocationGuard(bool disable = true) : m_disabled(disable) 586 { 587 if (!TEST_IS_CONSTANT_EVALUATED) { 588 // Don't re-disable if already disabled. 589 if (globalMemCounter.disable_allocations == true) m_disabled = false; 590 if (m_disabled) globalMemCounter.disableAllocations(); 591 } else { 592 m_disabled = false; 593 } 594 } 595 596 TEST_CONSTEXPR_CXX14 void release() { 597 if (!TEST_IS_CONSTANT_EVALUATED) { 598 if (m_disabled) globalMemCounter.enableAllocations(); 599 m_disabled = false; 600 } 601 } 602 603 TEST_CONSTEXPR_CXX20 ~ConstexprDisableAllocationGuard() { 604 release(); 605 } 606 607 private: 608 bool m_disabled; 609 610 ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&); 611 ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&); 612 }; 613 614 #endif 615 616 struct RequireAllocationGuard { 617 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) 618 : m_req_alloc(RequireAtLeast), 619 m_new_count_on_init(globalMemCounter.new_called), 620 m_outstanding_new_on_init(globalMemCounter.outstanding_new), 621 m_exactly(false) 622 { 623 } 624 625 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; } 626 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; } 627 628 ~RequireAllocationGuard() { 629 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init))); 630 std::size_t Expect = m_new_count_on_init + m_req_alloc; 631 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) || 632 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect)))); 633 } 634 635 private: 636 std::size_t m_req_alloc; 637 const std::size_t m_new_count_on_init; 638 const std::size_t m_outstanding_new_on_init; 639 bool m_exactly; 640 RequireAllocationGuard(RequireAllocationGuard const&); 641 RequireAllocationGuard& operator=(RequireAllocationGuard const&); 642 }; 643 644 #endif /* COUNT_NEW_H */ 645