• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
throw_bad_alloc_helper()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_ {};
MemCounter(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:
newCalled(std::size_t s)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 
alignedNewCalled(std::size_t s,std::size_t a)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 
deleteCalled(void * p)99     void deleteCalled(void * p)
100     {
101         assert(p);
102         --outstanding_new;
103         ++delete_called;
104     }
105 
alignedDeleteCalled(void * p,std::size_t a)106     void alignedDeleteCalled(void *p, std::size_t a) {
107       deleteCalled(p);
108       ++aligned_delete_called;
109       last_delete_align = a;
110     }
111 
newArrayCalled(std::size_t s)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 
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) const179     bool checkOutstandingNewEq(int n) const
180     {
181         return disable_checking || n == outstanding_new;
182     }
183 
checkOutstandingNewNotEq(int n) const184     bool checkOutstandingNewNotEq(int n) const
185     {
186         return disable_checking || n != outstanding_new;
187     }
188 
checkNewCalledEq(int n) const189     bool checkNewCalledEq(int n) const
190     {
191         return disable_checking || n == new_called;
192     }
193 
checkNewCalledNotEq(int n) const194     bool checkNewCalledNotEq(int n) const
195     {
196         return disable_checking || n != new_called;
197     }
198 
checkNewCalledGreaterThan(int n) const199     bool checkNewCalledGreaterThan(int n) const
200     {
201         return disable_checking || new_called > n;
202     }
203 
checkDeleteCalledEq(int n) const204     bool checkDeleteCalledEq(int n) const
205     {
206         return disable_checking || n == delete_called;
207     }
208 
checkDeleteCalledNotEq(int n) const209     bool checkDeleteCalledNotEq(int n) const
210     {
211         return disable_checking || n != delete_called;
212     }
213 
checkAlignedNewCalledEq(int n) const214     bool checkAlignedNewCalledEq(int n) const
215     {
216         return disable_checking || n == aligned_new_called;
217     }
218 
checkAlignedNewCalledNotEq(int n) const219     bool checkAlignedNewCalledNotEq(int n) const
220     {
221         return disable_checking || n != aligned_new_called;
222     }
223 
checkAlignedNewCalledGreaterThan(int n) const224     bool checkAlignedNewCalledGreaterThan(int n) const
225     {
226         return disable_checking || aligned_new_called > n;
227     }
228 
checkAlignedDeleteCalledEq(int n) const229     bool checkAlignedDeleteCalledEq(int n) const
230     {
231         return disable_checking || n == aligned_delete_called;
232     }
233 
checkAlignedDeleteCalledNotEq(int n) const234     bool checkAlignedDeleteCalledNotEq(int n) const
235     {
236         return disable_checking || n != aligned_delete_called;
237     }
238 
checkLastNewSizeEq(std::size_t n) const239     bool checkLastNewSizeEq(std::size_t n) const
240     {
241         return disable_checking || n == last_new_size;
242     }
243 
checkLastNewSizeNotEq(std::size_t n) const244     bool checkLastNewSizeNotEq(std::size_t n) const
245     {
246         return disable_checking || n != last_new_size;
247     }
248 
checkLastNewAlignEq(std::size_t n) const249     bool checkLastNewAlignEq(std::size_t n) const
250     {
251         return disable_checking || n == last_new_align;
252     }
253 
checkLastNewAlignNotEq(std::size_t n) const254     bool checkLastNewAlignNotEq(std::size_t n) const
255     {
256         return disable_checking || n != last_new_align;
257     }
258 
checkLastDeleteAlignEq(std::size_t n) const259     bool checkLastDeleteAlignEq(std::size_t n) const
260     {
261         return disable_checking || n == last_delete_align;
262     }
263 
checkLastDeleteAlignNotEq(std::size_t n) const264     bool checkLastDeleteAlignNotEq(std::size_t n) const
265     {
266         return disable_checking || n != last_delete_align;
267     }
268 
checkOutstandingArrayNewEq(int n) const269     bool checkOutstandingArrayNewEq(int n) const
270     {
271         return disable_checking || n == outstanding_array_new;
272     }
273 
checkOutstandingArrayNewNotEq(int n) const274     bool checkOutstandingArrayNewNotEq(int n) const
275     {
276         return disable_checking || n != outstanding_array_new;
277     }
278 
checkNewArrayCalledEq(int n) const279     bool checkNewArrayCalledEq(int n) const
280     {
281         return disable_checking || n == new_array_called;
282     }
283 
checkNewArrayCalledNotEq(int n) const284     bool checkNewArrayCalledNotEq(int n) const
285     {
286         return disable_checking || n != new_array_called;
287     }
288 
checkDeleteArrayCalledEq(int n) const289     bool checkDeleteArrayCalledEq(int n) const
290     {
291         return disable_checking || n == delete_array_called;
292     }
293 
checkDeleteArrayCalledNotEq(int n) const294     bool checkDeleteArrayCalledNotEq(int n) const
295     {
296         return disable_checking || n != delete_array_called;
297     }
298 
checkAlignedNewArrayCalledEq(int n) const299     bool checkAlignedNewArrayCalledEq(int n) const
300     {
301         return disable_checking || n == aligned_new_array_called;
302     }
303 
checkAlignedNewArrayCalledNotEq(int n) const304     bool checkAlignedNewArrayCalledNotEq(int n) const
305     {
306         return disable_checking || n != aligned_new_array_called;
307     }
308 
checkAlignedNewArrayCalledGreaterThan(int n) const309     bool checkAlignedNewArrayCalledGreaterThan(int n) const
310     {
311         return disable_checking || aligned_new_array_called > n;
312     }
313 
checkAlignedDeleteArrayCalledEq(int n) const314     bool checkAlignedDeleteArrayCalledEq(int n) const
315     {
316         return disable_checking || n == aligned_delete_array_called;
317     }
318 
checkAlignedDeleteArrayCalledNotEq(int n) const319     bool checkAlignedDeleteArrayCalledNotEq(int n) const
320     {
321         return disable_checking || n != aligned_delete_array_called;
322     }
323 
checkLastNewArraySizeEq(std::size_t n) const324     bool checkLastNewArraySizeEq(std::size_t n) const
325     {
326         return disable_checking || n == last_new_array_size;
327     }
328 
checkLastNewArraySizeNotEq(std::size_t n) const329     bool checkLastNewArraySizeNotEq(std::size_t n) const
330     {
331         return disable_checking || n != last_new_array_size;
332     }
333 
checkLastNewArrayAlignEq(std::size_t n) const334     bool checkLastNewArrayAlignEq(std::size_t n) const
335     {
336         return disable_checking || n == last_new_array_align;
337     }
338 
checkLastNewArrayAlignNotEq(std::size_t n) const339     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 
getGlobalMemCounter()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
operator new(std::size_t s)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 
operator delete(void * p)368 void  operator delete(void* p) TEST_NOEXCEPT
369 {
370     getGlobalMemCounter()->deleteCalled(p);
371     std::free(p);
372 }
373 
operator new[](std::size_t s)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 
operator delete[](void * p)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 
operator new(std::size_t s,std::align_val_t av)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 
operator delete(void * p,std::align_val_t av)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 
operator new[](std::size_t s,std::align_val_t av)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 
operator 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()->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 {
DisableAllocationGuardDisableAllocationGuard435     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 
releaseDisableAllocationGuard442     void release() {
443         if (m_disabled) globalMemCounter.enableAllocations();
444         m_disabled = false;
445     }
446 
~DisableAllocationGuardDisableAllocationGuard447     ~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 {
RequireAllocationGuardRequireAllocationGuard459     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 
requireAtLeastRequireAllocationGuard467     void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
requireExactlyRequireAllocationGuard468     void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
469 
~RequireAllocationGuardRequireAllocationGuard470     ~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 */
487