1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
17 #include <type_traits>
19 #include "test_macros.h"
21 #if defined(TEST_HAS_SANITIZERS)
22 #define DISABLE_NEW_COUNT
28 inline void throw_bad_alloc_helper() {
29 #ifndef TEST_HAS_NO_EXCEPTIONS
30 throw std::bad_alloc();
40 // Make MemCounter super hard to accidentally construct or copy.
41 class MemCounterCtorArg_
{};
42 explicit MemCounter(MemCounterCtorArg_
) { reset(); }
45 MemCounter(MemCounter
const &);
46 MemCounter
& operator=(MemCounter
const &);
49 // All checks return true when disable_checking is enabled.
50 static const bool disable_checking
;
52 // Disallow any allocations from occurring. Useful for testing that
53 // code doesn't perform any allocations.
54 bool disable_allocations
;
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);
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
;
70 int outstanding_array_new
;
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
;
80 void newCalled(std::size_t s
)
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
) {
94 void alignedNewCalled(std::size_t s
, std::size_t a
) {
100 void deleteCalled(void * p
)
107 void alignedDeleteCalled(void *p
, std::size_t a
) {
109 ++aligned_delete_called
;
110 last_delete_align
= a
;
113 void newArrayCalled(std::size_t s
)
115 assert(disable_allocations
== false);
116 if (throw_after
== 0) {
117 throw_after
= never_throw_value
;
118 detail::throw_bad_alloc_helper();
120 // don't decrement throw_after here. newCalled will end up doing that.
122 ++outstanding_array_new
;
124 last_new_array_size
= s
;
127 void alignedNewArrayCalled(std::size_t s
, std::size_t a
) {
129 ++aligned_new_array_called
;
130 last_new_array_align
= a
;
133 void deleteArrayCalled(void * p
)
136 --outstanding_array_new
;
137 ++delete_array_called
;
140 void alignedDeleteArrayCalled(void * p
, std::size_t a
) {
141 deleteArrayCalled(p
);
142 ++aligned_delete_array_called
;
143 last_delete_array_align
= a
;
146 void disableAllocations()
148 disable_allocations
= true;
151 void enableAllocations()
153 disable_allocations
= false;
158 disable_allocations
= false;
159 throw_after
= never_throw_value
;
164 aligned_new_called
= 0;
165 aligned_delete_called
= 0;
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;
179 bool checkOutstandingNewEq(int n
) const
181 return disable_checking
|| n
== outstanding_new
;
184 bool checkOutstandingNewNotEq(int n
) const
186 return disable_checking
|| n
!= outstanding_new
;
189 bool checkNewCalledEq(int n
) const
191 return disable_checking
|| n
== new_called
;
194 bool checkNewCalledNotEq(int n
) const
196 return disable_checking
|| n
!= new_called
;
199 bool checkNewCalledGreaterThan(int n
) const
201 return disable_checking
|| new_called
> n
;
204 bool checkDeleteCalledEq(int n
) const
206 return disable_checking
|| n
== delete_called
;
209 bool checkDeleteCalledNotEq(int n
) const
211 return disable_checking
|| n
!= delete_called
;
214 bool checkDeleteCalledGreaterThan(int n
) const
216 return disable_checking
|| delete_called
> n
;
219 bool checkAlignedNewCalledEq(int n
) const
221 return disable_checking
|| n
== aligned_new_called
;
224 bool checkAlignedNewCalledNotEq(int n
) const
226 return disable_checking
|| n
!= aligned_new_called
;
229 bool checkAlignedNewCalledGreaterThan(int n
) const
231 return disable_checking
|| aligned_new_called
> n
;
234 bool checkAlignedDeleteCalledEq(int n
) const
236 return disable_checking
|| n
== aligned_delete_called
;
239 bool checkAlignedDeleteCalledNotEq(int n
) const
241 return disable_checking
|| n
!= aligned_delete_called
;
244 bool checkLastNewSizeEq(std::size_t n
) const
246 return disable_checking
|| n
== last_new_size
;
249 bool checkLastNewSizeNotEq(std::size_t n
) const
251 return disable_checking
|| n
!= last_new_size
;
254 bool checkLastNewSizeGe(std::size_t n
) const
256 return disable_checking
|| last_new_size
>= n
;
259 bool checkLastNewAlignEq(std::size_t n
) const
261 return disable_checking
|| n
== last_new_align
;
264 bool checkLastNewAlignNotEq(std::size_t n
) const
266 return disable_checking
|| n
!= last_new_align
;
269 bool checkLastNewAlignGe(std::size_t n
) const
271 return disable_checking
|| last_new_align
>= n
;
274 bool checkLastDeleteAlignEq(std::size_t n
) const
276 return disable_checking
|| n
== last_delete_align
;
279 bool checkLastDeleteAlignNotEq(std::size_t n
) const
281 return disable_checking
|| n
!= last_delete_align
;
284 bool checkOutstandingArrayNewEq(int n
) const
286 return disable_checking
|| n
== outstanding_array_new
;
289 bool checkOutstandingArrayNewNotEq(int n
) const
291 return disable_checking
|| n
!= outstanding_array_new
;
294 bool checkNewArrayCalledEq(int n
) const
296 return disable_checking
|| n
== new_array_called
;
299 bool checkNewArrayCalledNotEq(int n
) const
301 return disable_checking
|| n
!= new_array_called
;
304 bool checkDeleteArrayCalledEq(int n
) const
306 return disable_checking
|| n
== delete_array_called
;
309 bool checkDeleteArrayCalledNotEq(int n
) const
311 return disable_checking
|| n
!= delete_array_called
;
314 bool checkAlignedNewArrayCalledEq(int n
) const
316 return disable_checking
|| n
== aligned_new_array_called
;
319 bool checkAlignedNewArrayCalledNotEq(int n
) const
321 return disable_checking
|| n
!= aligned_new_array_called
;
324 bool checkAlignedNewArrayCalledGreaterThan(int n
) const
326 return disable_checking
|| aligned_new_array_called
> n
;
329 bool checkAlignedDeleteArrayCalledEq(int n
) const
331 return disable_checking
|| n
== aligned_delete_array_called
;
334 bool checkAlignedDeleteArrayCalledNotEq(int n
) const
336 return disable_checking
|| n
!= aligned_delete_array_called
;
339 bool checkLastNewArraySizeEq(std::size_t n
) const
341 return disable_checking
|| n
== last_new_array_size
;
344 bool checkLastNewArraySizeNotEq(std::size_t n
) const
346 return disable_checking
|| n
!= last_new_array_size
;
349 bool checkLastNewArrayAlignEq(std::size_t n
) const
351 return disable_checking
|| n
== last_new_array_align
;
354 bool checkLastNewArrayAlignNotEq(std::size_t n
) const
356 return disable_checking
|| n
!= last_new_array_align
;
360 #ifdef DISABLE_NEW_COUNT
361 const bool MemCounter::disable_checking
= true;
363 const bool MemCounter::disable_checking
= false;
367 TEST_MSVC_DIAGNOSTIC_IGNORED(4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-)
368 inline MemCounter
* getGlobalMemCounter() {
369 static MemCounter
counter((MemCounter::MemCounterCtorArg_()));
374 MemCounter
&globalMemCounter
= *getGlobalMemCounter();
376 #ifndef DISABLE_NEW_COUNT
377 void* operator new(std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
)
379 getGlobalMemCounter()->newCalled(s
);
380 void* ret
= std::malloc(s
);
382 detail::throw_bad_alloc_helper();
386 void operator delete(void* p
) TEST_NOEXCEPT
388 getGlobalMemCounter()->deleteCalled(p
);
392 void* operator new[](std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
)
394 getGlobalMemCounter()->newArrayCalled(s
);
395 return operator new(s
);
398 void operator delete[](void* p
) TEST_NOEXCEPT
400 getGlobalMemCounter()->deleteArrayCalled(p
);
404 #ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
405 #if defined(_LIBCPP_MSVCRT_LIKE) || \
406 (!defined(_LIBCPP_VERSION) && defined(_WIN32))
407 #define USE_ALIGNED_ALLOC
410 void* operator new(std::size_t s
, std::align_val_t av
) TEST_THROW_SPEC(std::bad_alloc
) {
411 const std::size_t a
= static_cast<std::size_t>(av
);
412 getGlobalMemCounter()->alignedNewCalled(s
, a
);
414 #ifdef USE_ALIGNED_ALLOC
415 ret
= _aligned_malloc(s
, a
);
417 assert(posix_memalign(&ret
, std::max(a
, sizeof(void*)), s
) != EINVAL
);
420 detail::throw_bad_alloc_helper();
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()->alignedDeleteCalled(p
, a
);
428 #ifdef USE_ALIGNED_ALLOC
436 void* operator new[](std::size_t s
, std::align_val_t av
) TEST_THROW_SPEC(std::bad_alloc
) {
437 const std::size_t a
= static_cast<std::size_t>(av
);
438 getGlobalMemCounter()->alignedNewArrayCalled(s
, a
);
439 return operator new(s
, av
);
442 void operator delete[](void *p
, std::align_val_t av
) TEST_NOEXCEPT
{
443 const std::size_t a
= static_cast<std::size_t>(av
);
444 getGlobalMemCounter()->alignedDeleteArrayCalled(p
, a
);
445 return operator delete(p
, av
);
448 #endif // TEST_HAS_NO_ALIGNED_ALLOCATION
450 #endif // DISABLE_NEW_COUNT
452 struct DisableAllocationGuard
{
453 explicit DisableAllocationGuard(bool disable
= true) : m_disabled(disable
)
455 // Don't re-disable if already disabled.
456 if (globalMemCounter
.disable_allocations
== true) m_disabled
= false;
457 if (m_disabled
) globalMemCounter
.disableAllocations();
461 if (m_disabled
) globalMemCounter
.enableAllocations();
465 ~DisableAllocationGuard() {
472 DisableAllocationGuard(DisableAllocationGuard
const&);
473 DisableAllocationGuard
& operator=(DisableAllocationGuard
const&);
476 #if TEST_STD_VER >= 20
478 struct ConstexprDisableAllocationGuard
{
479 TEST_CONSTEXPR_CXX14
explicit ConstexprDisableAllocationGuard(bool disable
= true) : m_disabled(disable
)
481 if (!TEST_IS_CONSTANT_EVALUATED
) {
482 // Don't re-disable if already disabled.
483 if (globalMemCounter
.disable_allocations
== true) m_disabled
= false;
484 if (m_disabled
) globalMemCounter
.disableAllocations();
490 TEST_CONSTEXPR_CXX14
void release() {
491 if (!TEST_IS_CONSTANT_EVALUATED
) {
492 if (m_disabled
) globalMemCounter
.enableAllocations();
497 TEST_CONSTEXPR_CXX20
~ConstexprDisableAllocationGuard() {
504 ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard
const&);
505 ConstexprDisableAllocationGuard
& operator=(ConstexprDisableAllocationGuard
const&);
510 struct RequireAllocationGuard
{
511 explicit RequireAllocationGuard(std::size_t RequireAtLeast
= 1)
512 : m_req_alloc(RequireAtLeast
),
513 m_new_count_on_init(globalMemCounter
.new_called
),
514 m_outstanding_new_on_init(globalMemCounter
.outstanding_new
),
519 void requireAtLeast(std::size_t N
) { m_req_alloc
= N
; m_exactly
= false; }
520 void requireExactly(std::size_t N
) { m_req_alloc
= N
; m_exactly
= true; }
522 ~RequireAllocationGuard() {
523 assert(globalMemCounter
.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init
)));
524 std::size_t Expect
= m_new_count_on_init
+ m_req_alloc
;
525 assert(globalMemCounter
.checkNewCalledEq(static_cast<int>(Expect
)) ||
526 (!m_exactly
&& globalMemCounter
.checkNewCalledGreaterThan(static_cast<int>(Expect
))));
530 std::size_t m_req_alloc
;
531 const std::size_t m_new_count_on_init
;
532 const std::size_t m_outstanding_new_on_init
;
534 RequireAllocationGuard(RequireAllocationGuard
const&);
535 RequireAllocationGuard
& operator=(RequireAllocationGuard
const&);
538 #endif /* COUNT_NEW_H */