649 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef COUNT_NEW_H10#define COUNT_NEW_H11 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_COUNT23#endif24 25namespace detail26{27[[noreturn]] inline void throw_bad_alloc_helper() {28#ifndef TEST_HAS_NO_EXCEPTIONS29 throw std::bad_alloc();30#else31 std::abort();32#endif33}34}35 36class MemCounter37{38public:39 // Make MemCounter super hard to accidentally construct or copy.40 class MemCounterCtorArg_ {};41 explicit MemCounter(MemCounterCtorArg_) { reset(); }42 43private:44 MemCounter(MemCounter const &);45 MemCounter & operator=(MemCounter const &);46 47public: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 that52 // code doesn't perform any allocations.53 bool disable_allocations;54 55 // number of allocations to throw after. Default (unsigned)-1. If56 // 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 78public: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 180public:181 bool checkOutstandingNewEq(int n) const182 {183 return disable_checking || n == outstanding_new;184 }185 186 bool checkOutstandingNewLessThanOrEqual(int n) const187 {188 return disable_checking || outstanding_new <= n;189 }190 191 bool checkOutstandingNewNotEq(int n) const192 {193 return disable_checking || n != outstanding_new;194 }195 196 bool checkNewCalledEq(int n) const197 {198 return disable_checking || n == new_called;199 }200 201 bool checkNewCalledNotEq(int n) const202 {203 return disable_checking || n != new_called;204 }205 206 bool checkNewCalledGreaterThan(int n) const207 {208 return disable_checking || new_called > n;209 }210 211 bool checkDeleteCalledEq(int n) const212 {213 return disable_checking || n == delete_called;214 }215 216 bool checkDeleteCalledNotEq(int n) const217 {218 return disable_checking || n != delete_called;219 }220 221 bool checkDeleteCalledGreaterThan(int n) const222 {223 return disable_checking || delete_called > n;224 }225 226 bool checkAlignedNewCalledEq(int n) const227 {228 return disable_checking || n == aligned_new_called;229 }230 231 bool checkAlignedNewCalledNotEq(int n) const232 {233 return disable_checking || n != aligned_new_called;234 }235 236 bool checkAlignedNewCalledGreaterThan(int n) const237 {238 return disable_checking || aligned_new_called > n;239 }240 241 bool checkAlignedDeleteCalledEq(int n) const242 {243 return disable_checking || n == aligned_delete_called;244 }245 246 bool checkAlignedDeleteCalledNotEq(int n) const247 {248 return disable_checking || n != aligned_delete_called;249 }250 251 bool checkLastNewSizeEq(std::size_t n) const252 {253 return disable_checking || n == last_new_size;254 }255 256 bool checkLastNewSizeNotEq(std::size_t n) const257 {258 return disable_checking || n != last_new_size;259 }260 261 bool checkLastNewSizeGe(std::size_t n) const262 {263 return disable_checking || last_new_size >= n;264 }265 266 bool checkLastNewAlignEq(std::size_t n) const267 {268 return disable_checking || n == last_new_align;269 }270 271 bool checkLastNewAlignNotEq(std::size_t n) const272 {273 return disable_checking || n != last_new_align;274 }275 276 bool checkLastNewAlignGe(std::size_t n) const277 {278 return disable_checking || last_new_align >= n;279 }280 281 bool checkLastDeleteAlignEq(std::size_t n) const282 {283 return disable_checking || n == last_delete_align;284 }285 286 bool checkLastDeleteAlignNotEq(std::size_t n) const287 {288 return disable_checking || n != last_delete_align;289 }290 291 bool checkOutstandingArrayNewEq(int n) const292 {293 return disable_checking || n == outstanding_array_new;294 }295 296 bool checkOutstandingArrayNewNotEq(int n) const297 {298 return disable_checking || n != outstanding_array_new;299 }300 301 bool checkNewArrayCalledEq(int n) const302 {303 return disable_checking || n == new_array_called;304 }305 306 bool checkNewArrayCalledNotEq(int n) const307 {308 return disable_checking || n != new_array_called;309 }310 311 bool checkDeleteArrayCalledEq(int n) const312 {313 return disable_checking || n == delete_array_called;314 }315 316 bool checkDeleteArrayCalledNotEq(int n) const317 {318 return disable_checking || n != delete_array_called;319 }320 321 bool checkAlignedNewArrayCalledEq(int n) const322 {323 return disable_checking || n == aligned_new_array_called;324 }325 326 bool checkAlignedNewArrayCalledNotEq(int n) const327 {328 return disable_checking || n != aligned_new_array_called;329 }330 331 bool checkAlignedNewArrayCalledGreaterThan(int n) const332 {333 return disable_checking || aligned_new_array_called > n;334 }335 336 bool checkAlignedDeleteArrayCalledEq(int n) const337 {338 return disable_checking || n == aligned_delete_array_called;339 }340 341 bool checkAlignedDeleteArrayCalledNotEq(int n) const342 {343 return disable_checking || n != aligned_delete_array_called;344 }345 346 bool checkLastNewArraySizeEq(std::size_t n) const347 {348 return disable_checking || n == last_new_array_size;349 }350 351 bool checkLastNewArraySizeNotEq(std::size_t n) const352 {353 return disable_checking || n != last_new_array_size;354 }355 356 bool checkLastNewArrayAlignEq(std::size_t n) const357 {358 return disable_checking || n == last_new_array_align;359 }360 361 bool checkLastNewArrayAlignNotEq(std::size_t n) const362 {363 return disable_checking || n != last_new_array_align;364 }365};366 367#ifdef DISABLE_NEW_COUNT368 const bool MemCounter::disable_checking = true;369#else370 const bool MemCounter::disable_checking = false;371#endif372 373TEST_DIAGNOSTIC_PUSH374TEST_MSVC_DIAGNOSTIC_IGNORED(4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-)375inline MemCounter* getGlobalMemCounter() {376 static MemCounter counter((MemCounter::MemCounterCtorArg_()));377 return &counter;378}379TEST_DIAGNOSTIC_POP380 381MemCounter &globalMemCounter = *getGlobalMemCounter();382 383#ifndef DISABLE_NEW_COUNT384// operator new(size_t[, nothrow_t]) and operator delete(size_t[, nothrow_t])385void* 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 395void* operator new(std::size_t s, std::nothrow_t const&) TEST_NOEXCEPT {396# ifdef TEST_HAS_NO_EXCEPTIONS397 getGlobalMemCounter()->newCalled(s);398# else399 try {400 getGlobalMemCounter()->newCalled(s);401 } catch (std::bad_alloc const&) {402 return nullptr;403 }404# endif405 return std::malloc(s);406}407 408void operator delete(void* p) TEST_NOEXCEPT {409 getGlobalMemCounter()->deleteCalled(p);410 std::free(p);411}412 413void 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])419void* 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 429void* operator new[](std::size_t s, std::nothrow_t const&) TEST_NOEXCEPT {430# ifdef TEST_HAS_NO_EXCEPTIONS431 getGlobalMemCounter()->newArrayCalled(s);432# else433 try {434 getGlobalMemCounter()->newArrayCalled(s);435 } catch (std::bad_alloc const&) {436 return nullptr;437 }438# endif439 return std::malloc(s);440}441 442void operator delete[](void* p) TEST_NOEXCEPT {443 getGlobalMemCounter()->deleteArrayCalled(p);444 std::free(p);445}446 447void 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_ALLOCATION453# if defined(_LIBCPP_MSVCRT_LIKE) || (!defined(_LIBCPP_VERSION) && defined(_WIN32))454# define USE_ALIGNED_ALLOC455# endif456 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_ALLOC461# endif462# elif defined(__ANDROID__) && __ANDROID_API__ < 28463# define TEST_HAS_NO_C11_ALIGNED_ALLOC464# endif465 466inline 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_ALLOC470 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# else475 assert(posix_memalign(&ret, std::max(alignment, sizeof(void*)), size) != EINVAL);476# endif477 return ret;478}479 480inline void free_aligned_impl(void* ptr, std::align_val_t) {481 if (ptr) {482# ifdef USE_ALIGNED_ALLOC483 ::_aligned_free(ptr);484# else485 ::free(ptr);486# endif487 }488}489 490// operator new(size_t, align_val_t[, nothrow_t]) and operator delete(size_t, align_val_t[, nothrow_t])491void* 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 499void* operator new(std::size_t s, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT {500# ifdef TEST_HAS_NO_EXCEPTIONS501 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av));502# else503 try {504 getGlobalMemCounter()->alignedNewCalled(s, static_cast<std::size_t>(av));505 } catch (std::bad_alloc const&) {506 return nullptr;507 }508# endif509 return allocate_aligned_impl(s, av);510}511 512void 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 517void 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])523void* 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 531void* operator new[](std::size_t s, std::align_val_t av, std::nothrow_t const&) TEST_NOEXCEPT {532# ifdef TEST_HAS_NO_EXCEPTIONS533 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av));534# else535 try {536 getGlobalMemCounter()->alignedNewArrayCalled(s, static_cast<std::size_t>(av));537 } catch (std::bad_alloc const&) {538 return nullptr;539 }540# endif541 return allocate_aligned_impl(s, av);542}543 544void 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 549void 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_ALLOCATION555 556#endif // DISABLE_NEW_COUNT557 558struct 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 575private:576 bool m_disabled;577 578 DisableAllocationGuard(DisableAllocationGuard const&);579 DisableAllocationGuard& operator=(DisableAllocationGuard const&);580};581 582#if TEST_STD_VER >= 20583 584struct 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 607private:608 bool m_disabled;609 610 ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&);611 ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&);612};613 614#endif615 616struct 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#ifdef ALLOW_MISMATCHING_LIBRRARY_INTERNAL_ALLOCATIONS630 ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init)));631#else632 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init)));633#endif634 std::size_t Expect = m_new_count_on_init + m_req_alloc;635 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) ||636 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect))));637 }638 639private:640 std::size_t m_req_alloc;641 const std::size_t m_new_count_on_init;642 const std::size_t m_outstanding_new_on_init;643 bool m_exactly;644 RequireAllocationGuard(RequireAllocationGuard const&);645 RequireAllocationGuard& operator=(RequireAllocationGuard const&);646};647 648#endif /* COUNT_NEW_H */649