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