libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

count_new.hpp (12638B)


      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef COUNT_NEW_HPP
     11 #define COUNT_NEW_HPP
     12 
     13 # include <cstdlib>
     14 # include <cassert>
     15 # include <new>
     16 
     17 #include "test_macros.h"
     18 
     19 #if defined(TEST_HAS_SANITIZERS)
     20 #define DISABLE_NEW_COUNT
     21 #endif
     22 
     23 namespace detail
     24 {
     25    TEST_NORETURN
     26    inline void throw_bad_alloc_helper() {
     27 #ifndef TEST_HAS_NO_EXCEPTIONS
     28        throw std::bad_alloc();
     29 #else
     30        std::abort();
     31 #endif
     32    }
     33 }
     34 
     35 class MemCounter
     36 {
     37 public:
     38     // Make MemCounter super hard to accidentally construct or copy.
     39     class MemCounterCtorArg_ {};
     40     explicit MemCounter(MemCounterCtorArg_) { reset(); }
     41 
     42 private:
     43     MemCounter(MemCounter const &);
     44     MemCounter & operator=(MemCounter const &);
     45 
     46 public:
     47     // All checks return true when disable_checking is enabled.
     48     static const bool disable_checking;
     49 
     50     // Disallow any allocations from occurring. Useful for testing that
     51     // code doesn't perform any allocations.
     52     bool disable_allocations;
     53 
     54     // number of allocations to throw after. Default (unsigned)-1. If
     55     // throw_after has the default value it will never be decremented.
     56     static const unsigned never_throw_value = static_cast<unsigned>(-1);
     57     unsigned throw_after;
     58 
     59     int outstanding_new;
     60     int new_called;
     61     int delete_called;
     62     int aligned_new_called;
     63     int aligned_delete_called;
     64     std::size_t last_new_size;
     65     std::size_t last_new_align;
     66     std::size_t last_delete_align;
     67 
     68     int outstanding_array_new;
     69     int new_array_called;
     70     int delete_array_called;
     71     int aligned_new_array_called;
     72     int aligned_delete_array_called;
     73     std::size_t last_new_array_size;
     74     std::size_t last_new_array_align;
     75     std::size_t last_delete_array_align;
     76 
     77 public:
     78     void newCalled(std::size_t s)
     79     {
     80         assert(disable_allocations == false);
     81         assert(s);
     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         assert(p);
    102         --outstanding_new;
    103         ++delete_called;
    104     }
    105 
    106     void alignedDeleteCalled(void *p, std::size_t a) {
    107       deleteCalled(p);
    108       ++aligned_delete_called;
    109       last_delete_align = a;
    110     }
    111 
    112     void newArrayCalled(std::size_t s)
    113     {
    114         assert(disable_allocations == false);
    115         assert(s);
    116         if (throw_after == 0) {
    117             throw_after = never_throw_value;
    118             detail::throw_bad_alloc_helper();
    119         } else {
    120             // don't decrement throw_after here. newCalled will end up doing that.
    121         }
    122         ++outstanding_array_new;
    123         ++new_array_called;
    124         last_new_array_size = s;
    125     }
    126 
    127     void alignedNewArrayCalled(std::size_t s, std::size_t a) {
    128       newArrayCalled(s);
    129       ++aligned_new_array_called;
    130       last_new_array_align = a;
    131     }
    132 
    133     void deleteArrayCalled(void * p)
    134     {
    135         assert(p);
    136         --outstanding_array_new;
    137         ++delete_array_called;
    138     }
    139 
    140     void alignedDeleteArrayCalled(void * p, std::size_t a) {
    141       deleteArrayCalled(p);
    142       ++aligned_delete_array_called;
    143       last_delete_array_align = a;
    144     }
    145 
    146     void disableAllocations()
    147     {
    148         disable_allocations = true;
    149     }
    150 
    151     void enableAllocations()
    152     {
    153         disable_allocations = false;
    154     }
    155 
    156     void reset()
    157     {
    158         disable_allocations = false;
    159         throw_after = never_throw_value;
    160 
    161         outstanding_new = 0;
    162         new_called = 0;
    163         delete_called = 0;
    164         aligned_new_called = 0;
    165         aligned_delete_called = 0;
    166         last_new_size = 0;
    167         last_new_align = 0;
    168 
    169         outstanding_array_new = 0;
    170         new_array_called = 0;
    171         delete_array_called = 0;
    172         aligned_new_array_called = 0;
    173         aligned_delete_array_called = 0;
    174         last_new_array_size = 0;
    175         last_new_array_align = 0;
    176     }
    177 
    178 public:
    179     bool checkOutstandingNewEq(int n) const
    180     {
    181         return disable_checking || n == outstanding_new;
    182     }
    183 
    184     bool checkOutstandingNewNotEq(int n) const
    185     {
    186         return disable_checking || n != outstanding_new;
    187     }
    188 
    189     bool checkNewCalledEq(int n) const
    190     {
    191         return disable_checking || n == new_called;
    192     }
    193 
    194     bool checkNewCalledNotEq(int n) const
    195     {
    196         return disable_checking || n != new_called;
    197     }
    198 
    199     bool checkNewCalledGreaterThan(int n) const
    200     {
    201         return disable_checking || new_called > n;
    202     }
    203 
    204     bool checkDeleteCalledEq(int n) const
    205     {
    206         return disable_checking || n == delete_called;
    207     }
    208 
    209     bool checkDeleteCalledNotEq(int n) const
    210     {
    211         return disable_checking || n != delete_called;
    212     }
    213 
    214     bool checkAlignedNewCalledEq(int n) const
    215     {
    216         return disable_checking || n == aligned_new_called;
    217     }
    218 
    219     bool checkAlignedNewCalledNotEq(int n) const
    220     {
    221         return disable_checking || n != aligned_new_called;
    222     }
    223 
    224     bool checkAlignedNewCalledGreaterThan(int n) const
    225     {
    226         return disable_checking || aligned_new_called > n;
    227     }
    228 
    229     bool checkAlignedDeleteCalledEq(int n) const
    230     {
    231         return disable_checking || n == aligned_delete_called;
    232     }
    233 
    234     bool checkAlignedDeleteCalledNotEq(int n) const
    235     {
    236         return disable_checking || n != aligned_delete_called;
    237     }
    238 
    239     bool checkLastNewSizeEq(std::size_t n) const
    240     {
    241         return disable_checking || n == last_new_size;
    242     }
    243 
    244     bool checkLastNewSizeNotEq(std::size_t n) const
    245     {
    246         return disable_checking || n != last_new_size;
    247     }
    248 
    249     bool checkLastNewAlignEq(std::size_t n) const
    250     {
    251         return disable_checking || n == last_new_align;
    252     }
    253 
    254     bool checkLastNewAlignNotEq(std::size_t n) const
    255     {
    256         return disable_checking || n != last_new_align;
    257     }
    258 
    259     bool checkLastDeleteAlignEq(std::size_t n) const
    260     {
    261         return disable_checking || n == last_delete_align;
    262     }
    263 
    264     bool checkLastDeleteAlignNotEq(std::size_t n) const
    265     {
    266         return disable_checking || n != last_delete_align;
    267     }
    268 
    269     bool checkOutstandingArrayNewEq(int n) const
    270     {
    271         return disable_checking || n == outstanding_array_new;
    272     }
    273 
    274     bool checkOutstandingArrayNewNotEq(int n) const
    275     {
    276         return disable_checking || n != outstanding_array_new;
    277     }
    278 
    279     bool checkNewArrayCalledEq(int n) const
    280     {
    281         return disable_checking || n == new_array_called;
    282     }
    283 
    284     bool checkNewArrayCalledNotEq(int n) const
    285     {
    286         return disable_checking || n != new_array_called;
    287     }
    288 
    289     bool checkDeleteArrayCalledEq(int n) const
    290     {
    291         return disable_checking || n == delete_array_called;
    292     }
    293 
    294     bool checkDeleteArrayCalledNotEq(int n) const
    295     {
    296         return disable_checking || n != delete_array_called;
    297     }
    298 
    299     bool checkAlignedNewArrayCalledEq(int n) const
    300     {
    301         return disable_checking || n == aligned_new_array_called;
    302     }
    303 
    304     bool checkAlignedNewArrayCalledNotEq(int n) const
    305     {
    306         return disable_checking || n != aligned_new_array_called;
    307     }
    308 
    309     bool checkAlignedNewArrayCalledGreaterThan(int n) const
    310     {
    311         return disable_checking || aligned_new_array_called > n;
    312     }
    313 
    314     bool checkAlignedDeleteArrayCalledEq(int n) const
    315     {
    316         return disable_checking || n == aligned_delete_array_called;
    317     }
    318 
    319     bool checkAlignedDeleteArrayCalledNotEq(int n) const
    320     {
    321         return disable_checking || n != aligned_delete_array_called;
    322     }
    323 
    324     bool checkLastNewArraySizeEq(std::size_t n) const
    325     {
    326         return disable_checking || n == last_new_array_size;
    327     }
    328 
    329     bool checkLastNewArraySizeNotEq(std::size_t n) const
    330     {
    331         return disable_checking || n != last_new_array_size;
    332     }
    333 
    334     bool checkLastNewArrayAlignEq(std::size_t n) const
    335     {
    336         return disable_checking || n == last_new_array_align;
    337     }
    338 
    339     bool checkLastNewArrayAlignNotEq(std::size_t n) const
    340     {
    341         return disable_checking || n != last_new_array_align;
    342     }
    343 };
    344 
    345 #ifdef DISABLE_NEW_COUNT
    346   const bool MemCounter::disable_checking = true;
    347 #else
    348   const bool MemCounter::disable_checking = false;
    349 #endif
    350 
    351 inline MemCounter* getGlobalMemCounter() {
    352   static MemCounter counter((MemCounter::MemCounterCtorArg_()));
    353   return &counter;
    354 }
    355 
    356 MemCounter &globalMemCounter = *getGlobalMemCounter();
    357 
    358 #ifndef DISABLE_NEW_COUNT
    359 void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
    360 {
    361     getGlobalMemCounter()->newCalled(s);
    362     void* ret = std::malloc(s);
    363     if (ret == nullptr)
    364         detail::throw_bad_alloc_helper();
    365     return ret;
    366 }
    367 
    368 void  operator delete(void* p) TEST_NOEXCEPT
    369 {
    370     getGlobalMemCounter()->deleteCalled(p);
    371     std::free(p);
    372 }
    373 
    374 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
    375 {
    376     getGlobalMemCounter()->newArrayCalled(s);
    377     return operator new(s);
    378 }
    379 
    380 void operator delete[](void* p) TEST_NOEXCEPT
    381 {
    382     getGlobalMemCounter()->deleteArrayCalled(p);
    383     operator delete(p);
    384 }
    385 
    386 #ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
    387 #if defined(_LIBCPP_MSVCRT_LIKE) || \
    388   (!defined(_LIBCPP_VERSION) && defined(_WIN32))
    389 #define USE_ALIGNED_ALLOC
    390 #endif
    391 
    392 void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) {
    393   const std::size_t a = static_cast<std::size_t>(av);
    394   getGlobalMemCounter()->alignedNewCalled(s, a);
    395   void *ret;
    396 #ifdef USE_ALIGNED_ALLOC
    397   ret = _aligned_malloc(s, a);
    398 #else
    399   posix_memalign(&ret, a, s);
    400 #endif
    401   if (ret == nullptr)
    402     detail::throw_bad_alloc_helper();
    403   return ret;
    404 }
    405 
    406 void operator delete(void *p, std::align_val_t av) TEST_NOEXCEPT {
    407   const std::size_t a = static_cast<std::size_t>(av);
    408   getGlobalMemCounter()->alignedDeleteCalled(p, a);
    409   if (p) {
    410 #ifdef USE_ALIGNED_ALLOC
    411     ::_aligned_free(p);
    412 #else
    413     ::free(p);
    414 #endif
    415   }
    416 }
    417 
    418 void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) {
    419   const std::size_t a = static_cast<std::size_t>(av);
    420   getGlobalMemCounter()->alignedNewArrayCalled(s, a);
    421   return operator new(s, av);
    422 }
    423 
    424 void operator delete[](void *p, std::align_val_t av) TEST_NOEXCEPT {
    425   const std::size_t a = static_cast<std::size_t>(av);
    426   getGlobalMemCounter()->alignedDeleteArrayCalled(p, a);
    427   return operator delete(p, av);
    428 }
    429 
    430 #endif // TEST_HAS_NO_ALIGNED_ALLOCATION
    431 
    432 #endif // DISABLE_NEW_COUNT
    433 
    434 struct DisableAllocationGuard {
    435     explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
    436     {
    437         // Don't re-disable if already disabled.
    438         if (globalMemCounter.disable_allocations == true) m_disabled = false;
    439         if (m_disabled) globalMemCounter.disableAllocations();
    440     }
    441 
    442     void release() {
    443         if (m_disabled) globalMemCounter.enableAllocations();
    444         m_disabled = false;
    445     }
    446 
    447     ~DisableAllocationGuard() {
    448         release();
    449     }
    450 
    451 private:
    452     bool m_disabled;
    453 
    454     DisableAllocationGuard(DisableAllocationGuard const&);
    455     DisableAllocationGuard& operator=(DisableAllocationGuard const&);
    456 };
    457 
    458 struct RequireAllocationGuard {
    459     explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
    460             : m_req_alloc(RequireAtLeast),
    461               m_new_count_on_init(globalMemCounter.new_called),
    462               m_outstanding_new_on_init(globalMemCounter.outstanding_new),
    463               m_exactly(false)
    464     {
    465     }
    466 
    467     void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
    468     void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
    469 
    470     ~RequireAllocationGuard() {
    471         assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init)));
    472         std::size_t Expect = m_new_count_on_init + m_req_alloc;
    473         assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) ||
    474                (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect))));
    475     }
    476 
    477 private:
    478     std::size_t m_req_alloc;
    479     const std::size_t m_new_count_on_init;
    480     const std::size_t m_outstanding_new_on_init;
    481     bool m_exactly;
    482     RequireAllocationGuard(RequireAllocationGuard const&);
    483     RequireAllocationGuard& operator=(RequireAllocationGuard const&);
    484 };
    485 
    486 #endif /* COUNT_NEW_HPP */