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
27 [[noreturn
]] inline void throw_bad_alloc_helper() {
28 #ifndef TEST_HAS_NO_EXCEPTIONS
29 throw std::bad_alloc();
39 // Make MemCounter super hard to accidentally construct or copy.
40 class MemCounterCtorArg_
{};
41 explicit MemCounter(MemCounterCtorArg_
) { reset(); }
44 MemCounter(MemCounter
const &);
45 MemCounter
& operator=(MemCounter
const &);
48 // All checks return true when disable_checking is enabled.
49 static const bool disable_checking
;
51 // Disallow any allocations from occurring. Useful for testing that
52 // code doesn't perform any allocations.
53 bool disable_allocations
;
55 // number of allocations to throw after. Default (unsigned)-1. If
56 // throw_after has the default value it will never be decremented.
57 static const unsigned never_throw_value
= static_cast<unsigned>(-1);
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
;
69 int outstanding_array_new
;
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
;
79 void newCalled(std::size_t s
)
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
) {
93 void alignedNewCalled(std::size_t s
, std::size_t a
) {
99 void deleteCalled(void * p
)
107 void alignedDeleteCalled(void *p
, std::size_t a
) {
110 ++aligned_delete_called
;
111 last_delete_align
= a
;
115 void newArrayCalled(std::size_t s
)
117 assert(disable_allocations
== false);
118 if (throw_after
== 0) {
119 throw_after
= never_throw_value
;
120 detail::throw_bad_alloc_helper();
122 // don't decrement throw_after here. newCalled will end up doing that.
124 ++outstanding_array_new
;
126 last_new_array_size
= s
;
129 void alignedNewArrayCalled(std::size_t s
, std::size_t a
) {
131 ++aligned_new_array_called
;
132 last_new_array_align
= a
;
135 void deleteArrayCalled(void * p
)
138 --outstanding_array_new
;
139 ++delete_array_called
;
142 void alignedDeleteArrayCalled(void * p
, std::size_t a
) {
143 deleteArrayCalled(p
);
144 ++aligned_delete_array_called
;
145 last_delete_array_align
= a
;
148 void disableAllocations()
150 disable_allocations
= true;
153 void enableAllocations()
155 disable_allocations
= false;
160 disable_allocations
= false;
161 throw_after
= never_throw_value
;
166 aligned_new_called
= 0;
167 aligned_delete_called
= 0;
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;
181 bool checkOutstandingNewEq(int n
) const
183 return disable_checking
|| n
== outstanding_new
;
186 bool checkOutstandingNewLessThanOrEqual(int n
) const
188 return disable_checking
|| outstanding_new
<= n
;
191 bool checkOutstandingNewNotEq(int n
) const
193 return disable_checking
|| n
!= outstanding_new
;
196 bool checkNewCalledEq(int n
) const
198 return disable_checking
|| n
== new_called
;
201 bool checkNewCalledNotEq(int n
) const
203 return disable_checking
|| n
!= new_called
;
206 bool checkNewCalledGreaterThan(int n
) const
208 return disable_checking
|| new_called
> n
;
211 bool checkDeleteCalledEq(int n
) const
213 return disable_checking
|| n
== delete_called
;
216 bool checkDeleteCalledNotEq(int n
) const
218 return disable_checking
|| n
!= delete_called
;
221 bool checkDeleteCalledGreaterThan(int n
) const
223 return disable_checking
|| delete_called
> n
;
226 bool checkAlignedNewCalledEq(int n
) const
228 return disable_checking
|| n
== aligned_new_called
;
231 bool checkAlignedNewCalledNotEq(int n
) const
233 return disable_checking
|| n
!= aligned_new_called
;
236 bool checkAlignedNewCalledGreaterThan(int n
) const
238 return disable_checking
|| aligned_new_called
> n
;
241 bool checkAlignedDeleteCalledEq(int n
) const
243 return disable_checking
|| n
== aligned_delete_called
;
246 bool checkAlignedDeleteCalledNotEq(int n
) const
248 return disable_checking
|| n
!= aligned_delete_called
;
251 bool checkLastNewSizeEq(std::size_t n
) const
253 return disable_checking
|| n
== last_new_size
;
256 bool checkLastNewSizeNotEq(std::size_t n
) const
258 return disable_checking
|| n
!= last_new_size
;
261 bool checkLastNewSizeGe(std::size_t n
) const
263 return disable_checking
|| last_new_size
>= n
;
266 bool checkLastNewAlignEq(std::size_t n
) const
268 return disable_checking
|| n
== last_new_align
;
271 bool checkLastNewAlignNotEq(std::size_t n
) const
273 return disable_checking
|| n
!= last_new_align
;
276 bool checkLastNewAlignGe(std::size_t n
) const
278 return disable_checking
|| last_new_align
>= n
;
281 bool checkLastDeleteAlignEq(std::size_t n
) const
283 return disable_checking
|| n
== last_delete_align
;
286 bool checkLastDeleteAlignNotEq(std::size_t n
) const
288 return disable_checking
|| n
!= last_delete_align
;
291 bool checkOutstandingArrayNewEq(int n
) const
293 return disable_checking
|| n
== outstanding_array_new
;
296 bool checkOutstandingArrayNewNotEq(int n
) const
298 return disable_checking
|| n
!= outstanding_array_new
;
301 bool checkNewArrayCalledEq(int n
) const
303 return disable_checking
|| n
== new_array_called
;
306 bool checkNewArrayCalledNotEq(int n
) const
308 return disable_checking
|| n
!= new_array_called
;
311 bool checkDeleteArrayCalledEq(int n
) const
313 return disable_checking
|| n
== delete_array_called
;
316 bool checkDeleteArrayCalledNotEq(int n
) const
318 return disable_checking
|| n
!= delete_array_called
;
321 bool checkAlignedNewArrayCalledEq(int n
) const
323 return disable_checking
|| n
== aligned_new_array_called
;
326 bool checkAlignedNewArrayCalledNotEq(int n
) const
328 return disable_checking
|| n
!= aligned_new_array_called
;
331 bool checkAlignedNewArrayCalledGreaterThan(int n
) const
333 return disable_checking
|| aligned_new_array_called
> n
;
336 bool checkAlignedDeleteArrayCalledEq(int n
) const
338 return disable_checking
|| n
== aligned_delete_array_called
;
341 bool checkAlignedDeleteArrayCalledNotEq(int n
) const
343 return disable_checking
|| n
!= aligned_delete_array_called
;
346 bool checkLastNewArraySizeEq(std::size_t n
) const
348 return disable_checking
|| n
== last_new_array_size
;
351 bool checkLastNewArraySizeNotEq(std::size_t n
) const
353 return disable_checking
|| n
!= last_new_array_size
;
356 bool checkLastNewArrayAlignEq(std::size_t n
) const
358 return disable_checking
|| n
== last_new_array_align
;
361 bool checkLastNewArrayAlignNotEq(std::size_t n
) const
363 return disable_checking
|| n
!= last_new_array_align
;
367 #ifdef DISABLE_NEW_COUNT
368 const bool MemCounter::disable_checking
= true;
370 const bool MemCounter::disable_checking
= false;
374 TEST_MSVC_DIAGNOSTIC_IGNORED(4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-)
375 inline MemCounter
* getGlobalMemCounter() {
376 static MemCounter
counter((MemCounter::MemCounterCtorArg_()));
381 MemCounter
&globalMemCounter
= *getGlobalMemCounter();
383 #ifndef DISABLE_NEW_COUNT
384 // operator new(size_t[, nothrow_t]) and operator delete(size_t[, nothrow_t])
385 void* operator new(std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
) {
386 getGlobalMemCounter()->newCalled(s
);
389 void* p
= std::malloc(s
);
391 detail::throw_bad_alloc_helper();
395 void* operator new(std::size_t s
, std::nothrow_t
const&) TEST_NOEXCEPT
{
396 # ifdef TEST_HAS_NO_EXCEPTIONS
397 getGlobalMemCounter()->newCalled(s
);
400 getGlobalMemCounter()->newCalled(s
);
401 } catch (std::bad_alloc
const&) {
405 return std::malloc(s
);
408 void operator delete(void* p
) TEST_NOEXCEPT
{
409 getGlobalMemCounter()->deleteCalled(p
);
413 void operator delete(void* p
, std::nothrow_t
const&) TEST_NOEXCEPT
{
414 getGlobalMemCounter()->deleteCalled(p
);
418 // operator new[](size_t[, nothrow_t]) and operator delete[](size_t[, nothrow_t])
419 void* operator new[](std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
) {
420 getGlobalMemCounter()->newArrayCalled(s
);
423 void* p
= std::malloc(s
);
425 detail::throw_bad_alloc_helper();
429 void* operator new[](std::size_t s
, std::nothrow_t
const&) TEST_NOEXCEPT
{
430 # ifdef TEST_HAS_NO_EXCEPTIONS
431 getGlobalMemCounter()->newArrayCalled(s
);
434 getGlobalMemCounter()->newArrayCalled(s
);
435 } catch (std::bad_alloc
const&) {
439 return std::malloc(s
);
442 void operator delete[](void* p
) TEST_NOEXCEPT
{
443 getGlobalMemCounter()->deleteArrayCalled(p
);
447 void operator delete[](void* p
, std::nothrow_t
const&) TEST_NOEXCEPT
{
448 getGlobalMemCounter()->deleteArrayCalled(p
);
452 # ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
453 # if defined(_LIBCPP_MSVCRT_LIKE) || (!defined(_LIBCPP_VERSION) && defined(_WIN32))
454 # define USE_ALIGNED_ALLOC
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_ALLOC
462 # elif defined(__ANDROID__) && __ANDROID_API__ < 28
463 # define TEST_HAS_NO_C11_ALIGNED_ALLOC
466 inline 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
);
469 # ifdef USE_ALIGNED_ALLOC
470 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
);
475 assert(posix_memalign(&ret
, std::max(alignment
, sizeof(void*)), size
) != EINVAL
);
480 inline void free_aligned_impl(void* ptr
, std::align_val_t
) {
482 # ifdef USE_ALIGNED_ALLOC
483 ::_aligned_free(ptr
);
490 // operator new(size_t, align_val_t[, nothrow_t]) and operator delete(size_t, align_val_t[, nothrow_t])
491 void* 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
);
495 detail::throw_bad_alloc_helper();
499 void* operator new(std::size_t s
, std::align_val_t av
, std::nothrow_t
const&) TEST_NOEXCEPT
{
500 # ifdef TEST_HAS_NO_EXCEPTIONS
501 getGlobalMemCounter()->alignedNewCalled(s
, static_cast<std::size_t>(av
));
504 getGlobalMemCounter()->alignedNewCalled(s
, static_cast<std::size_t>(av
));
505 } catch (std::bad_alloc
const&) {
509 return allocate_aligned_impl(s
, av
);
512 void 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
);
517 void 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
);
522 // operator new[](size_t, align_val_t[, nothrow_t]) and operator delete[](size_t, align_val_t[, nothrow_t])
523 void* 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
);
527 detail::throw_bad_alloc_helper();
531 void* operator new[](std::size_t s
, std::align_val_t av
, std::nothrow_t
const&) TEST_NOEXCEPT
{
532 # ifdef TEST_HAS_NO_EXCEPTIONS
533 getGlobalMemCounter()->alignedNewArrayCalled(s
, static_cast<std::size_t>(av
));
536 getGlobalMemCounter()->alignedNewArrayCalled(s
, static_cast<std::size_t>(av
));
537 } catch (std::bad_alloc
const&) {
541 return allocate_aligned_impl(s
, av
);
544 void 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
);
549 void 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
);
554 # endif // TEST_HAS_NO_ALIGNED_ALLOCATION
556 #endif // DISABLE_NEW_COUNT
558 struct DisableAllocationGuard
{
559 explicit DisableAllocationGuard(bool disable
= true) : m_disabled(disable
)
561 // Don't re-disable if already disabled.
562 if (globalMemCounter
.disable_allocations
== true) m_disabled
= false;
563 if (m_disabled
) globalMemCounter
.disableAllocations();
567 if (m_disabled
) globalMemCounter
.enableAllocations();
571 ~DisableAllocationGuard() {
578 DisableAllocationGuard(DisableAllocationGuard
const&);
579 DisableAllocationGuard
& operator=(DisableAllocationGuard
const&);
582 #if TEST_STD_VER >= 20
584 struct ConstexprDisableAllocationGuard
{
585 TEST_CONSTEXPR_CXX14
explicit ConstexprDisableAllocationGuard(bool disable
= true) : m_disabled(disable
)
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();
596 TEST_CONSTEXPR_CXX14
void release() {
597 if (!TEST_IS_CONSTANT_EVALUATED
) {
598 if (m_disabled
) globalMemCounter
.enableAllocations();
603 TEST_CONSTEXPR_CXX20
~ConstexprDisableAllocationGuard() {
610 ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard
const&);
611 ConstexprDisableAllocationGuard
& operator=(ConstexprDisableAllocationGuard
const&);
616 struct 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
),
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; }
628 ~RequireAllocationGuard() {
629 assert(globalMemCounter
.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init
)));
630 std::size_t Expect
= m_new_count_on_init
+ m_req_alloc
;
631 assert(globalMemCounter
.checkNewCalledEq(static_cast<int>(Expect
)) ||
632 (!m_exactly
&& globalMemCounter
.checkNewCalledGreaterThan(static_cast<int>(Expect
))));
636 std::size_t m_req_alloc
;
637 const std::size_t m_new_count_on_init
;
638 const std::size_t m_outstanding_new_on_init
;
640 RequireAllocationGuard(RequireAllocationGuard
const&);
641 RequireAllocationGuard
& operator=(RequireAllocationGuard
const&);
644 #endif /* COUNT_NEW_H */