• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef COUNT_NEW_H
10 #define COUNT_NEW_H
11 
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_COUNT
23 #endif
24 
25 namespace detail
26 {
27    TEST_NORETURN
throw_bad_alloc_helper()28    inline void throw_bad_alloc_helper() {
29 #ifndef TEST_HAS_NO_EXCEPTIONS
30        throw std::bad_alloc();
31 #else
32        std::abort();
33 #endif
34    }
35 }
36 
37 class MemCounter
38 {
39 public:
40     // Make MemCounter super hard to accidentally construct or copy.
41     class MemCounterCtorArg_ {};
MemCounter(MemCounterCtorArg_)42     explicit MemCounter(MemCounterCtorArg_) { reset(); }
43 
44 private:
45     MemCounter(MemCounter const &);
46     MemCounter & operator=(MemCounter const &);
47 
48 public:
49     // All checks return true when disable_checking is enabled.
50     static const bool disable_checking;
51 
52     // Disallow any allocations from occurring. Useful for testing that
53     // code doesn't perform any allocations.
54     bool disable_allocations;
55 
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);
59     unsigned throw_after;
60 
61     int outstanding_new;
62     int new_called;
63     int delete_called;
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;
69 
70     int outstanding_array_new;
71     int new_array_called;
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;
78 
79 public:
newCalled(std::size_t s)80     void newCalled(std::size_t s)
81     {
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) {
87             --throw_after;
88         }
89         ++new_called;
90         ++outstanding_new;
91         last_new_size = s;
92     }
93 
alignedNewCalled(std::size_t s,std::size_t a)94     void alignedNewCalled(std::size_t s, std::size_t a) {
95       newCalled(s);
96       ++aligned_new_called;
97       last_new_align = a;
98     }
99 
deleteCalled(void * p)100     void deleteCalled(void * p)
101     {
102         assert(p);
103         --outstanding_new;
104         ++delete_called;
105     }
106 
alignedDeleteCalled(void * p,std::size_t a)107     void alignedDeleteCalled(void *p, std::size_t a) {
108       deleteCalled(p);
109       ++aligned_delete_called;
110       last_delete_align = a;
111     }
112 
newArrayCalled(std::size_t s)113     void newArrayCalled(std::size_t s)
114     {
115         assert(disable_allocations == false);
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 
alignedNewArrayCalled(std::size_t s,std::size_t a)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 
deleteArrayCalled(void * p)133     void deleteArrayCalled(void * p)
134     {
135         assert(p);
136         --outstanding_array_new;
137         ++delete_array_called;
138     }
139 
alignedDeleteArrayCalled(void * p,std::size_t a)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 
disableAllocations()146     void disableAllocations()
147     {
148         disable_allocations = true;
149     }
150 
enableAllocations()151     void enableAllocations()
152     {
153         disable_allocations = false;
154     }
155 
reset()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:
checkOutstandingNewEq(int n)179     bool checkOutstandingNewEq(int n) const
180     {
181         return disable_checking || n == outstanding_new;
182     }
183 
checkOutstandingNewNotEq(int n)184     bool checkOutstandingNewNotEq(int n) const
185     {
186         return disable_checking || n != outstanding_new;
187     }
188 
checkNewCalledEq(int n)189     bool checkNewCalledEq(int n) const
190     {
191         return disable_checking || n == new_called;
192     }
193 
checkNewCalledNotEq(int n)194     bool checkNewCalledNotEq(int n) const
195     {
196         return disable_checking || n != new_called;
197     }
198 
checkNewCalledGreaterThan(int n)199     bool checkNewCalledGreaterThan(int n) const
200     {
201         return disable_checking || new_called > n;
202     }
203 
checkDeleteCalledEq(int n)204     bool checkDeleteCalledEq(int n) const
205     {
206         return disable_checking || n == delete_called;
207     }
208 
checkDeleteCalledNotEq(int n)209     bool checkDeleteCalledNotEq(int n) const
210     {
211         return disable_checking || n != delete_called;
212     }
213 
checkDeleteCalledGreaterThan(int n)214     bool checkDeleteCalledGreaterThan(int n) const
215     {
216         return disable_checking || delete_called > n;
217     }
218 
checkAlignedNewCalledEq(int n)219     bool checkAlignedNewCalledEq(int n) const
220     {
221         return disable_checking || n == aligned_new_called;
222     }
223 
checkAlignedNewCalledNotEq(int n)224     bool checkAlignedNewCalledNotEq(int n) const
225     {
226         return disable_checking || n != aligned_new_called;
227     }
228 
checkAlignedNewCalledGreaterThan(int n)229     bool checkAlignedNewCalledGreaterThan(int n) const
230     {
231         return disable_checking || aligned_new_called > n;
232     }
233 
checkAlignedDeleteCalledEq(int n)234     bool checkAlignedDeleteCalledEq(int n) const
235     {
236         return disable_checking || n == aligned_delete_called;
237     }
238 
checkAlignedDeleteCalledNotEq(int n)239     bool checkAlignedDeleteCalledNotEq(int n) const
240     {
241         return disable_checking || n != aligned_delete_called;
242     }
243 
checkLastNewSizeEq(std::size_t n)244     bool checkLastNewSizeEq(std::size_t n) const
245     {
246         return disable_checking || n == last_new_size;
247     }
248 
checkLastNewSizeNotEq(std::size_t n)249     bool checkLastNewSizeNotEq(std::size_t n) const
250     {
251         return disable_checking || n != last_new_size;
252     }
253 
checkLastNewSizeGe(std::size_t n)254     bool checkLastNewSizeGe(std::size_t n) const
255     {
256         return disable_checking || last_new_size >= n;
257     }
258 
checkLastNewAlignEq(std::size_t n)259     bool checkLastNewAlignEq(std::size_t n) const
260     {
261         return disable_checking || n == last_new_align;
262     }
263 
checkLastNewAlignNotEq(std::size_t n)264     bool checkLastNewAlignNotEq(std::size_t n) const
265     {
266         return disable_checking || n != last_new_align;
267     }
268 
checkLastNewAlignGe(std::size_t n)269     bool checkLastNewAlignGe(std::size_t n) const
270     {
271         return disable_checking || last_new_align >= n;
272     }
273 
checkLastDeleteAlignEq(std::size_t n)274     bool checkLastDeleteAlignEq(std::size_t n) const
275     {
276         return disable_checking || n == last_delete_align;
277     }
278 
checkLastDeleteAlignNotEq(std::size_t n)279     bool checkLastDeleteAlignNotEq(std::size_t n) const
280     {
281         return disable_checking || n != last_delete_align;
282     }
283 
checkOutstandingArrayNewEq(int n)284     bool checkOutstandingArrayNewEq(int n) const
285     {
286         return disable_checking || n == outstanding_array_new;
287     }
288 
checkOutstandingArrayNewNotEq(int n)289     bool checkOutstandingArrayNewNotEq(int n) const
290     {
291         return disable_checking || n != outstanding_array_new;
292     }
293 
checkNewArrayCalledEq(int n)294     bool checkNewArrayCalledEq(int n) const
295     {
296         return disable_checking || n == new_array_called;
297     }
298 
checkNewArrayCalledNotEq(int n)299     bool checkNewArrayCalledNotEq(int n) const
300     {
301         return disable_checking || n != new_array_called;
302     }
303 
checkDeleteArrayCalledEq(int n)304     bool checkDeleteArrayCalledEq(int n) const
305     {
306         return disable_checking || n == delete_array_called;
307     }
308 
checkDeleteArrayCalledNotEq(int n)309     bool checkDeleteArrayCalledNotEq(int n) const
310     {
311         return disable_checking || n != delete_array_called;
312     }
313 
checkAlignedNewArrayCalledEq(int n)314     bool checkAlignedNewArrayCalledEq(int n) const
315     {
316         return disable_checking || n == aligned_new_array_called;
317     }
318 
checkAlignedNewArrayCalledNotEq(int n)319     bool checkAlignedNewArrayCalledNotEq(int n) const
320     {
321         return disable_checking || n != aligned_new_array_called;
322     }
323 
checkAlignedNewArrayCalledGreaterThan(int n)324     bool checkAlignedNewArrayCalledGreaterThan(int n) const
325     {
326         return disable_checking || aligned_new_array_called > n;
327     }
328 
checkAlignedDeleteArrayCalledEq(int n)329     bool checkAlignedDeleteArrayCalledEq(int n) const
330     {
331         return disable_checking || n == aligned_delete_array_called;
332     }
333 
checkAlignedDeleteArrayCalledNotEq(int n)334     bool checkAlignedDeleteArrayCalledNotEq(int n) const
335     {
336         return disable_checking || n != aligned_delete_array_called;
337     }
338 
checkLastNewArraySizeEq(std::size_t n)339     bool checkLastNewArraySizeEq(std::size_t n) const
340     {
341         return disable_checking || n == last_new_array_size;
342     }
343 
checkLastNewArraySizeNotEq(std::size_t n)344     bool checkLastNewArraySizeNotEq(std::size_t n) const
345     {
346         return disable_checking || n != last_new_array_size;
347     }
348 
checkLastNewArrayAlignEq(std::size_t n)349     bool checkLastNewArrayAlignEq(std::size_t n) const
350     {
351         return disable_checking || n == last_new_array_align;
352     }
353 
checkLastNewArrayAlignNotEq(std::size_t n)354     bool checkLastNewArrayAlignNotEq(std::size_t n) const
355     {
356         return disable_checking || n != last_new_array_align;
357     }
358 };
359 
360 #ifdef DISABLE_NEW_COUNT
361   const bool MemCounter::disable_checking = true;
362 #else
363   const bool MemCounter::disable_checking = false;
364 #endif
365 
366 TEST_DIAGNOSTIC_PUSH
367 TEST_MSVC_DIAGNOSTIC_IGNORED(4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-)
getGlobalMemCounter()368 inline MemCounter* getGlobalMemCounter() {
369   static MemCounter counter((MemCounter::MemCounterCtorArg_()));
370   return &counter;
371 }
372 TEST_DIAGNOSTIC_POP
373 
374 MemCounter &globalMemCounter = *getGlobalMemCounter();
375 
376 #ifndef DISABLE_NEW_COUNT
new(std::size_t s)377 void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
378 {
379     getGlobalMemCounter()->newCalled(s);
380     void* ret = std::malloc(s);
381     if (ret == nullptr)
382         detail::throw_bad_alloc_helper();
383     return ret;
384 }
385 
delete(void * p)386 void  operator delete(void* p) TEST_NOEXCEPT
387 {
388     getGlobalMemCounter()->deleteCalled(p);
389     std::free(p);
390 }
391 
TEST_THROW_SPEC(std::bad_alloc)392 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
393 {
394     getGlobalMemCounter()->newArrayCalled(s);
395     return operator new(s);
396 }
397 
398 void operator delete[](void* p) TEST_NOEXCEPT
399 {
400     getGlobalMemCounter()->deleteArrayCalled(p);
401     operator delete(p);
402 }
403 
404 #ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
405 #if defined(_LIBCPP_MSVCRT_LIKE) || \
406   (!defined(_LIBCPP_VERSION) && defined(_WIN32))
407 #define USE_ALIGNED_ALLOC
408 #endif
409 
new(std::size_t s,std::align_val_t av)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);
413   void *ret = nullptr;
414 #ifdef USE_ALIGNED_ALLOC
415   ret = _aligned_malloc(s, a);
416 #else
417   assert(posix_memalign(&ret, std::max(a, sizeof(void*)), s) != EINVAL);
418 #endif
419   if (ret == nullptr)
420     detail::throw_bad_alloc_helper();
421   return ret;
422 }
423 
delete(void * p,std::align_val_t av)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);
427   if (p) {
428 #ifdef USE_ALIGNED_ALLOC
429     ::_aligned_free(p);
430 #else
431     ::free(p);
432 #endif
433   }
434 }
435 
TEST_THROW_SPEC(std::bad_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);
440 }
441 
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);
446 }
447 
448 #endif // TEST_HAS_NO_ALIGNED_ALLOCATION
449 
450 #endif // DISABLE_NEW_COUNT
451 
452 struct DisableAllocationGuard {
m_disabledDisableAllocationGuard453     explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
454     {
455         // Don't re-disable if already disabled.
456         if (globalMemCounter.disable_allocations == true) m_disabled = false;
457         if (m_disabled) globalMemCounter.disableAllocations();
458     }
459 
releaseDisableAllocationGuard460     void release() {
461         if (m_disabled) globalMemCounter.enableAllocations();
462         m_disabled = false;
463     }
464 
~DisableAllocationGuardDisableAllocationGuard465     ~DisableAllocationGuard() {
466         release();
467     }
468 
469 private:
470     bool m_disabled;
471 
472     DisableAllocationGuard(DisableAllocationGuard const&);
473     DisableAllocationGuard& operator=(DisableAllocationGuard const&);
474 };
475 
476 #if TEST_STD_VER >= 20
477 
478 struct ConstexprDisableAllocationGuard {
m_disabledConstexprDisableAllocationGuard479     TEST_CONSTEXPR_CXX14 explicit ConstexprDisableAllocationGuard(bool disable = true) : m_disabled(disable)
480     {
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();
485         } else {
486             m_disabled = false;
487         }
488     }
489 
releaseConstexprDisableAllocationGuard490     TEST_CONSTEXPR_CXX14 void release() {
491         if (!TEST_IS_CONSTANT_EVALUATED) {
492             if (m_disabled) globalMemCounter.enableAllocations();
493             m_disabled = false;
494         }
495     }
496 
~ConstexprDisableAllocationGuardConstexprDisableAllocationGuard497     TEST_CONSTEXPR_CXX20 ~ConstexprDisableAllocationGuard() {
498         release();
499     }
500 
501 private:
502     bool m_disabled;
503 
504     ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&);
505     ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&);
506 };
507 
508 #endif
509 
510 struct RequireAllocationGuard {
511     explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
m_req_allocRequireAllocationGuard512             : m_req_alloc(RequireAtLeast),
513               m_new_count_on_init(globalMemCounter.new_called),
514               m_outstanding_new_on_init(globalMemCounter.outstanding_new),
515               m_exactly(false)
516     {
517     }
518 
requireAtLeastRequireAllocationGuard519     void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
requireExactlyRequireAllocationGuard520     void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
521 
~RequireAllocationGuardRequireAllocationGuard522     ~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))));
527     }
528 
529 private:
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;
533     bool m_exactly;
534     RequireAllocationGuard(RequireAllocationGuard const&);
535     RequireAllocationGuard& operator=(RequireAllocationGuard const&);
536 };
537 
538 #endif /* COUNT_NEW_H */
539