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 void* p = std::malloc(s); 389 if (p == nullptr) 390 detail::throw_bad_alloc_helper(); 391 return p; 392 } 393 394 void* operator new(std::size_t s, std::nothrow_t const&) TEST_NOEXCEPT { 395 # ifdef TEST_HAS_NO_EXCEPTIONS 396 getGlobalMemCounter()->newCalled(s); 397 # else 398 try { 399 getGlobalMemCounter()->newCalled(s); 400 } catch (std::bad_alloc const&) { 401 return nullptr; 402 } 403 # endif 404 return std::malloc(s); 405 } 406 407 void operator delete(void* p) TEST_NOEXCEPT { 408 getGlobalMemCounter()->deleteCalled(p); 409 std::free(p); 410 } 411 412 void operator delete(void* p, std::nothrow_t const&) TEST_NOEXCEPT { 413 getGlobalMemCounter()->deleteCalled(p); 414 std::free(p); 415 } 416 417 // operator new[](size_t[, nothrow_t]) and operator delete[](size_t[, nothrow_t]) 418 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc) { 419 getGlobalMemCounter()->newArrayCalled(s); 420 void* p = std::malloc(s); 421 if (p == nullptr) 422 detail::throw_bad_alloc_helper(); 423 return p; 424 } 425 426 void* operator new[](std::size_t s, std::nothrow_t const&) TEST_NOEXCEPT { 427 # ifdef TEST_HAS_NO_EXCEPTIONS 428 getGlobalMemCounter()->newArrayCalled(s); 429 # else 430 try { 431 getGlobalMemCounter()->newArrayCalled(s); 432 } catch (std::bad_alloc const&) { 433 return nullptr; 434 } 435 # endif 436 return std::malloc(s); 437 } 438 439 void operator delete[](void* p) TEST_NOEXCEPT { 440 getGlobalMemCounter()->deleteArrayCalled(p); 441 std::free(p); 442 } 443 444 void operator delete[](void* p, std::nothrow_t const&) TEST_NOEXCEPT { 445 getGlobalMemCounter()->deleteArrayCalled(p); 446 std::free(p); 447 } 448 449 # ifndef TEST_HAS_NO_ALIGNED_ALLOCATION 450 # if defined(_LIBCPP_MSVCRT_LIKE) || (!defined(_LIBCPP_VERSION) && defined(_WIN32)) 451 # define USE_ALIGNED_ALLOC 452 # endif 453 454 inline void* alocate_aligned_impl(std::size_t size, std::align_val_t align) { 455 const std::size_t alignment = static_cast<std::size_t>(align); 456 void* ret = nullptr; 457 # ifdef USE_ALIGNED_ALLOC 458 ret = _aligned_malloc(size, alignment); 459 # else 460 assert(posix_memalign(&ret, std::max(alignment, sizeof(void*)), size) != EINVAL); 461 # endif 462 return ret; 463 } 464 465 inline void free_aligned_impl(void* ptr, std::align_val_t) { 466 if (ptr) { 467 # ifdef USE_ALIGNED_ALLOC 468 ::_aligned_free(ptr); 469 # else 470 ::free(ptr); 471 # endif 472 } 473 } 474 475 // operator new(size_t, align_val_t[, nothrow_t]) and operator delete(size_t, align_val_t[, nothrow_t]) 476 void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { 477 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av)); 478 void* p = alocate_aligned_impl(s, av); 479 if (p == nullptr) 480 detail::throw_bad_alloc_helper(); 481 return p; 482 } 483 484 void* operator new(std::size_t s, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 485 # ifdef TEST_HAS_NO_EXCEPTIONS 486 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av)); 487 # else 488 try { 489 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av)); 490 } catch (std::bad_alloc const&) { 491 return nullptr; 492 } 493 # endif 494 return alocate_aligned_impl(s, av); 495 } 496 497 void operator delete(void* p, std::align_val_t av) TEST_NOEXCEPT { 498 getGlobalMemCounter()->alignedDeleteCalled(p, static_cast<std::size_t>(av)); 499 free_aligned_impl(p, av); 500 } 501 502 void operator delete(void* p, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 503 getGlobalMemCounter()->alignedDeleteCalled(p, static_cast<std::size_t>(av)); 504 free_aligned_impl(p, av); 505 } 506 507 // operator new[](size_t, align_val_t[, nothrow_t]) and operator delete[](size_t, align_val_t[, nothrow_t]) 508 void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) { 509 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av)); 510 void* p = alocate_aligned_impl(s, av); 511 if (p == nullptr) 512 detail::throw_bad_alloc_helper(); 513 return p; 514 } 515 516 void* operator new[](std::size_t s, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 517 # ifdef TEST_HAS_NO_EXCEPTIONS 518 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av)); 519 # else 520 try { 521 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av)); 522 } catch (std::bad_alloc const&) { 523 return nullptr; 524 } 525 # endif 526 return alocate_aligned_impl(s, av); 527 } 528 529 void operator delete[](void* p, std::align_val_t av) TEST_NOEXCEPT { 530 getGlobalMemCounter()->alignedDeleteArrayCalled(p, static_cast<std::size_t>(av)); 531 free_aligned_impl(p, av); 532 } 533 534 void operator delete[](void* p, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT { 535 getGlobalMemCounter()->alignedDeleteArrayCalled(p, static_cast<std::size_t>(av)); 536 free_aligned_impl(p, av); 537 } 538 539 # endif // TEST_HAS_NO_ALIGNED_ALLOCATION 540 541 #endif // DISABLE_NEW_COUNT 542 543 struct DisableAllocationGuard { 544 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable) 545 { 546 // Don't re-disable if already disabled. 547 if (globalMemCounter.disable_allocations == true) m_disabled = false; 548 if (m_disabled) globalMemCounter.disableAllocations(); 549 } 550 551 void release() { 552 if (m_disabled) globalMemCounter.enableAllocations(); 553 m_disabled = false; 554 } 555 556 ~DisableAllocationGuard() { 557 release(); 558 } 559 560 private: 561 bool m_disabled; 562 563 DisableAllocationGuard(DisableAllocationGuard const&); 564 DisableAllocationGuard& operator=(DisableAllocationGuard const&); 565 }; 566 567 #if TEST_STD_VER >= 20 568 569 struct ConstexprDisableAllocationGuard { 570 TEST_CONSTEXPR_CXX14 explicit ConstexprDisableAllocationGuard(bool disable = true) : m_disabled(disable) 571 { 572 if (!TEST_IS_CONSTANT_EVALUATED) { 573 // Don't re-disable if already disabled. 574 if (globalMemCounter.disable_allocations == true) m_disabled = false; 575 if (m_disabled) globalMemCounter.disableAllocations(); 576 } else { 577 m_disabled = false; 578 } 579 } 580 581 TEST_CONSTEXPR_CXX14 void release() { 582 if (!TEST_IS_CONSTANT_EVALUATED) { 583 if (m_disabled) globalMemCounter.enableAllocations(); 584 m_disabled = false; 585 } 586 } 587 588 TEST_CONSTEXPR_CXX20 ~ConstexprDisableAllocationGuard() { 589 release(); 590 } 591 592 private: 593 bool m_disabled; 594 595 ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&); 596 ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&); 597 }; 598 599 #endif 600 601 struct RequireAllocationGuard { 602 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) 603 : m_req_alloc(RequireAtLeast), 604 m_new_count_on_init(globalMemCounter.new_called), 605 m_outstanding_new_on_init(globalMemCounter.outstanding_new), 606 m_exactly(false) 607 { 608 } 609 610 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; } 611 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; } 612 613 ~RequireAllocationGuard() { 614 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init))); 615 std::size_t Expect = m_new_count_on_init + m_req_alloc; 616 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) || 617 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect)))); 618 } 619 620 private: 621 std::size_t m_req_alloc; 622 const std::size_t m_new_count_on_init; 623 const std::size_t m_outstanding_new_on_init; 624 bool m_exactly; 625 RequireAllocationGuard(RequireAllocationGuard const&); 626 RequireAllocationGuard& operator=(RequireAllocationGuard const&); 627 }; 628 629 #endif /* COUNT_NEW_H */ 630