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