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 //===----------------------------------------------------------------------===//
16 #include "test_macros.h"
18 #if defined(TEST_HAS_SANITIZERS)
19 #define DISABLE_NEW_COUNT
25 inline void throw_bad_alloc_helper() {
26 #ifndef TEST_HAS_NO_EXCEPTIONS
27 throw std::bad_alloc();
37 // Make MemCounter super hard to accidentally construct or copy.
38 class MemCounterCtorArg_
{};
39 explicit MemCounter(MemCounterCtorArg_
) { reset(); }
42 MemCounter(MemCounter
const &);
43 MemCounter
& operator=(MemCounter
const &);
46 // All checks return true when disable_checking is enabled.
47 static const bool disable_checking
;
49 // Disallow any allocations from occurring. Useful for testing that
50 // code doesn't perform any allocations.
51 bool disable_allocations
;
53 // number of allocations to throw after. Default (unsigned)-1. If
54 // throw_after has the default value it will never be decremented.
55 static const unsigned never_throw_value
= static_cast<unsigned>(-1);
61 int aligned_new_called
;
62 int aligned_delete_called
;
63 std::size_t last_new_size
;
64 std::size_t last_new_align
;
65 std::size_t last_delete_align
;
67 int outstanding_array_new
;
69 int delete_array_called
;
70 int aligned_new_array_called
;
71 int aligned_delete_array_called
;
72 std::size_t last_new_array_size
;
73 std::size_t last_new_array_align
;
74 std::size_t last_delete_array_align
;
77 void newCalled(std::size_t s
)
79 assert(disable_allocations
== false);
81 if (throw_after
== 0) {
82 throw_after
= never_throw_value
;
83 detail::throw_bad_alloc_helper();
84 } else if (throw_after
!= never_throw_value
) {
92 void alignedNewCalled(std::size_t s
, std::size_t a
) {
98 void deleteCalled(void * p
)
105 void alignedDeleteCalled(void *p
, std::size_t a
) {
107 ++aligned_delete_called
;
108 last_delete_align
= a
;
111 void newArrayCalled(std::size_t s
)
113 assert(disable_allocations
== false);
115 if (throw_after
== 0) {
116 throw_after
= never_throw_value
;
117 detail::throw_bad_alloc_helper();
119 // don't decrement throw_after here. newCalled will end up doing that.
121 ++outstanding_array_new
;
123 last_new_array_size
= s
;
126 void alignedNewArrayCalled(std::size_t s
, std::size_t a
) {
128 ++aligned_new_array_called
;
129 last_new_array_align
= a
;
132 void deleteArrayCalled(void * p
)
135 --outstanding_array_new
;
136 ++delete_array_called
;
139 void alignedDeleteArrayCalled(void * p
, std::size_t a
) {
140 deleteArrayCalled(p
);
141 ++aligned_delete_array_called
;
142 last_delete_array_align
= a
;
145 void disableAllocations()
147 disable_allocations
= true;
150 void enableAllocations()
152 disable_allocations
= false;
157 disable_allocations
= false;
158 throw_after
= never_throw_value
;
163 aligned_new_called
= 0;
164 aligned_delete_called
= 0;
168 outstanding_array_new
= 0;
169 new_array_called
= 0;
170 delete_array_called
= 0;
171 aligned_new_array_called
= 0;
172 aligned_delete_array_called
= 0;
173 last_new_array_size
= 0;
174 last_new_array_align
= 0;
178 bool checkOutstandingNewEq(int n
) const
180 return disable_checking
|| n
== outstanding_new
;
183 bool checkOutstandingNewNotEq(int n
) const
185 return disable_checking
|| n
!= outstanding_new
;
188 bool checkNewCalledEq(int n
) const
190 return disable_checking
|| n
== new_called
;
193 bool checkNewCalledNotEq(int n
) const
195 return disable_checking
|| n
!= new_called
;
198 bool checkNewCalledGreaterThan(int n
) const
200 return disable_checking
|| new_called
> n
;
203 bool checkDeleteCalledEq(int n
) const
205 return disable_checking
|| n
== delete_called
;
208 bool checkDeleteCalledNotEq(int n
) const
210 return disable_checking
|| n
!= delete_called
;
213 bool checkAlignedNewCalledEq(int n
) const
215 return disable_checking
|| n
== aligned_new_called
;
218 bool checkAlignedNewCalledNotEq(int n
) const
220 return disable_checking
|| n
!= aligned_new_called
;
223 bool checkAlignedNewCalledGreaterThan(int n
) const
225 return disable_checking
|| aligned_new_called
> n
;
228 bool checkAlignedDeleteCalledEq(int n
) const
230 return disable_checking
|| n
== aligned_delete_called
;
233 bool checkAlignedDeleteCalledNotEq(int n
) const
235 return disable_checking
|| n
!= aligned_delete_called
;
238 bool checkLastNewSizeEq(std::size_t n
) const
240 return disable_checking
|| n
== last_new_size
;
243 bool checkLastNewSizeNotEq(std::size_t n
) const
245 return disable_checking
|| n
!= last_new_size
;
248 bool checkLastNewAlignEq(std::size_t n
) const
250 return disable_checking
|| n
== last_new_align
;
253 bool checkLastNewAlignNotEq(std::size_t n
) const
255 return disable_checking
|| n
!= last_new_align
;
258 bool checkLastDeleteAlignEq(std::size_t n
) const
260 return disable_checking
|| n
== last_delete_align
;
263 bool checkLastDeleteAlignNotEq(std::size_t n
) const
265 return disable_checking
|| n
!= last_delete_align
;
268 bool checkOutstandingArrayNewEq(int n
) const
270 return disable_checking
|| n
== outstanding_array_new
;
273 bool checkOutstandingArrayNewNotEq(int n
) const
275 return disable_checking
|| n
!= outstanding_array_new
;
278 bool checkNewArrayCalledEq(int n
) const
280 return disable_checking
|| n
== new_array_called
;
283 bool checkNewArrayCalledNotEq(int n
) const
285 return disable_checking
|| n
!= new_array_called
;
288 bool checkDeleteArrayCalledEq(int n
) const
290 return disable_checking
|| n
== delete_array_called
;
293 bool checkDeleteArrayCalledNotEq(int n
) const
295 return disable_checking
|| n
!= delete_array_called
;
298 bool checkAlignedNewArrayCalledEq(int n
) const
300 return disable_checking
|| n
== aligned_new_array_called
;
303 bool checkAlignedNewArrayCalledNotEq(int n
) const
305 return disable_checking
|| n
!= aligned_new_array_called
;
308 bool checkAlignedNewArrayCalledGreaterThan(int n
) const
310 return disable_checking
|| aligned_new_array_called
> n
;
313 bool checkAlignedDeleteArrayCalledEq(int n
) const
315 return disable_checking
|| n
== aligned_delete_array_called
;
318 bool checkAlignedDeleteArrayCalledNotEq(int n
) const
320 return disable_checking
|| n
!= aligned_delete_array_called
;
323 bool checkLastNewArraySizeEq(std::size_t n
) const
325 return disable_checking
|| n
== last_new_array_size
;
328 bool checkLastNewArraySizeNotEq(std::size_t n
) const
330 return disable_checking
|| n
!= last_new_array_size
;
333 bool checkLastNewArrayAlignEq(std::size_t n
) const
335 return disable_checking
|| n
== last_new_array_align
;
338 bool checkLastNewArrayAlignNotEq(std::size_t n
) const
340 return disable_checking
|| n
!= last_new_array_align
;
344 #ifdef DISABLE_NEW_COUNT
345 const bool MemCounter::disable_checking
= true;
347 const bool MemCounter::disable_checking
= false;
351 #pragma warning(push)
352 #pragma warning(disable: 4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-)
354 inline MemCounter
* getGlobalMemCounter() {
355 static MemCounter
counter((MemCounter::MemCounterCtorArg_()));
362 MemCounter
&globalMemCounter
= *getGlobalMemCounter();
364 #ifndef DISABLE_NEW_COUNT
365 void* operator new(std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
)
367 getGlobalMemCounter()->newCalled(s
);
368 void* ret
= std::malloc(s
);
370 detail::throw_bad_alloc_helper();
374 void operator delete(void* p
) TEST_NOEXCEPT
376 getGlobalMemCounter()->deleteCalled(p
);
380 void* operator new[](std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
)
382 getGlobalMemCounter()->newArrayCalled(s
);
383 return operator new(s
);
386 void operator delete[](void* p
) TEST_NOEXCEPT
388 getGlobalMemCounter()->deleteArrayCalled(p
);
392 #ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
393 #if defined(_LIBCPP_MSVCRT_LIKE) || \
394 (!defined(_LIBCPP_VERSION) && defined(_WIN32))
395 #define USE_ALIGNED_ALLOC
398 void* operator new(std::size_t s
, std::align_val_t av
) TEST_THROW_SPEC(std::bad_alloc
) {
399 const std::size_t a
= static_cast<std::size_t>(av
);
400 getGlobalMemCounter()->alignedNewCalled(s
, a
);
402 #ifdef USE_ALIGNED_ALLOC
403 ret
= _aligned_malloc(s
, a
);
405 posix_memalign(&ret
, a
, s
);
408 detail::throw_bad_alloc_helper();
412 void operator delete(void *p
, std::align_val_t av
) TEST_NOEXCEPT
{
413 const std::size_t a
= static_cast<std::size_t>(av
);
414 getGlobalMemCounter()->alignedDeleteCalled(p
, a
);
416 #ifdef USE_ALIGNED_ALLOC
424 void* operator new[](std::size_t s
, std::align_val_t av
) TEST_THROW_SPEC(std::bad_alloc
) {
425 const std::size_t a
= static_cast<std::size_t>(av
);
426 getGlobalMemCounter()->alignedNewArrayCalled(s
, a
);
427 return operator new(s
, av
);
430 void operator delete[](void *p
, std::align_val_t av
) TEST_NOEXCEPT
{
431 const std::size_t a
= static_cast<std::size_t>(av
);
432 getGlobalMemCounter()->alignedDeleteArrayCalled(p
, a
);
433 return operator delete(p
, av
);
436 #endif // TEST_HAS_NO_ALIGNED_ALLOCATION
438 #endif // DISABLE_NEW_COUNT
440 struct DisableAllocationGuard
{
441 explicit DisableAllocationGuard(bool disable
= true) : m_disabled(disable
)
443 // Don't re-disable if already disabled.
444 if (globalMemCounter
.disable_allocations
== true) m_disabled
= false;
445 if (m_disabled
) globalMemCounter
.disableAllocations();
449 if (m_disabled
) globalMemCounter
.enableAllocations();
453 ~DisableAllocationGuard() {
460 DisableAllocationGuard(DisableAllocationGuard
const&);
461 DisableAllocationGuard
& operator=(DisableAllocationGuard
const&);
464 struct RequireAllocationGuard
{
465 explicit RequireAllocationGuard(std::size_t RequireAtLeast
= 1)
466 : m_req_alloc(RequireAtLeast
),
467 m_new_count_on_init(globalMemCounter
.new_called
),
468 m_outstanding_new_on_init(globalMemCounter
.outstanding_new
),
473 void requireAtLeast(std::size_t N
) { m_req_alloc
= N
; m_exactly
= false; }
474 void requireExactly(std::size_t N
) { m_req_alloc
= N
; m_exactly
= true; }
476 ~RequireAllocationGuard() {
477 assert(globalMemCounter
.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init
)));
478 std::size_t Expect
= m_new_count_on_init
+ m_req_alloc
;
479 assert(globalMemCounter
.checkNewCalledEq(static_cast<int>(Expect
)) ||
480 (!m_exactly
&& globalMemCounter
.checkNewCalledGreaterThan(static_cast<int>(Expect
))));
484 std::size_t m_req_alloc
;
485 const std::size_t m_new_count_on_init
;
486 const std::size_t m_outstanding_new_on_init
;
488 RequireAllocationGuard(RequireAllocationGuard
const&);
489 RequireAllocationGuard
& operator=(RequireAllocationGuard
const&);
492 #endif /* COUNT_NEW_H */