brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.7 KiB · f175bc2 Raw
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