blob: c001c0340fa2d2c51a32518705c42353960880ce [file] [log] [blame]
Eric Fiselier38236b52016-01-19 21:52:04 +00001//===----------------------------------------------------------------------===//
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
Eric Fiselier2cbc6542014-12-22 22:38:59 +000010#ifndef COUNT_NEW_HPP
11#define COUNT_NEW_HPP
12
13# include <cstdlib>
14# include <cassert>
15# include <new>
16
Eric Fiselierf2f2a632016-06-14 21:31:42 +000017#include "test_macros.h"
Eric Fiselier5a4ee412015-01-27 23:03:38 +000018
Eric Fiselier37400712016-06-26 19:42:59 +000019#if defined(TEST_HAS_SANITIZERS)
Eric Fiselier2cbc6542014-12-22 22:38:59 +000020#define DISABLE_NEW_COUNT
21#endif
22
Eric Fiselier8ff74322016-06-22 03:46:32 +000023namespace detail
24{
Eric Fiselier37400712016-06-26 19:42:59 +000025 TEST_NORETURN
Eric Fiselier8ff74322016-06-22 03:46:32 +000026 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
Eric Fiselier2cbc6542014-12-22 22:38:59 +000035class MemCounter
36{
37public:
38 // Make MemCounter super hard to accidentally construct or copy.
39 class MemCounterCtorArg_ {};
Eric Fiselier85b788c2015-02-10 15:17:46 +000040 explicit MemCounter(MemCounterCtorArg_) { reset(); }
Eric Fiselier2cbc6542014-12-22 22:38:59 +000041
42private:
43 MemCounter(MemCounter const &);
44 MemCounter & operator=(MemCounter const &);
45
46public:
47 // All checks return true when disable_checking is enabled.
48 static const bool disable_checking;
49
Eric Fiselier3461dbc2015-07-31 02:24:58 +000050 // Disallow any allocations from occurring. Useful for testing that
51 // code doesn't perform any allocations.
52 bool disable_allocations;
53
Eric Fiselier8ff74322016-06-22 03:46:32 +000054 // 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
Eric Fiselier85b788c2015-02-10 15:17:46 +000059 int outstanding_new;
60 int new_called;
61 int delete_called;
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +000062 std::size_t last_new_size;
Eric Fiselier2cbc6542014-12-22 22:38:59 +000063
Eric Fiselier85b788c2015-02-10 15:17:46 +000064 int outstanding_array_new;
65 int new_array_called;
66 int delete_array_called;
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +000067 std::size_t last_new_array_size;
Eric Fiselier2cbc6542014-12-22 22:38:59 +000068
69public:
70 void newCalled(std::size_t s)
71 {
Eric Fiselier3461dbc2015-07-31 02:24:58 +000072 assert(disable_allocations == false);
Eric Fiselier2cbc6542014-12-22 22:38:59 +000073 assert(s);
Eric Fiselier8ff74322016-06-22 03:46:32 +000074 if (throw_after == 0) {
75 throw_after = never_throw_value;
76 detail::throw_bad_alloc_helper();
77 } else if (throw_after != never_throw_value) {
78 --throw_after;
79 }
Eric Fiselier2cbc6542014-12-22 22:38:59 +000080 ++new_called;
81 ++outstanding_new;
82 last_new_size = s;
83 }
84
85 void deleteCalled(void * p)
86 {
87 assert(p);
88 --outstanding_new;
89 ++delete_called;
90 }
91
92 void newArrayCalled(std::size_t s)
93 {
Eric Fiselier3461dbc2015-07-31 02:24:58 +000094 assert(disable_allocations == false);
Eric Fiselier2cbc6542014-12-22 22:38:59 +000095 assert(s);
Eric Fiselier8ff74322016-06-22 03:46:32 +000096 if (throw_after == 0) {
97 throw_after = never_throw_value;
98 detail::throw_bad_alloc_helper();
99 } else {
100 // don't decrement throw_after here. newCalled will end up doing that.
101 }
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000102 ++outstanding_array_new;
103 ++new_array_called;
104 last_new_array_size = s;
105 }
106
107 void deleteArrayCalled(void * p)
108 {
109 assert(p);
110 --outstanding_array_new;
111 ++delete_array_called;
112 }
113
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000114 void disableAllocations()
115 {
116 disable_allocations = true;
117 }
118
119 void enableAllocations()
120 {
121 disable_allocations = false;
122 }
123
Eric Fiselier8ff74322016-06-22 03:46:32 +0000124
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000125 void reset()
126 {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000127 disable_allocations = false;
Eric Fiselier8ff74322016-06-22 03:46:32 +0000128 throw_after = never_throw_value;
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000129
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000130 outstanding_new = 0;
131 new_called = 0;
132 delete_called = 0;
133 last_new_size = 0;
134
135 outstanding_array_new = 0;
136 new_array_called = 0;
137 delete_array_called = 0;
138 last_new_array_size = 0;
139 }
140
141public:
142 bool checkOutstandingNewEq(int n) const
143 {
144 return disable_checking || n == outstanding_new;
145 }
146
147 bool checkOutstandingNewNotEq(int n) const
148 {
149 return disable_checking || n != outstanding_new;
150 }
151
152 bool checkNewCalledEq(int n) const
153 {
154 return disable_checking || n == new_called;
155 }
156
157 bool checkNewCalledNotEq(int n) const
158 {
159 return disable_checking || n != new_called;
160 }
161
Eric Fiselierc7979582016-06-17 19:46:40 +0000162 bool checkNewCalledGreaterThan(int n) const
163 {
164 return disable_checking || new_called > n;
165 }
166
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000167 bool checkDeleteCalledEq(int n) const
168 {
169 return disable_checking || n == delete_called;
170 }
171
172 bool checkDeleteCalledNotEq(int n) const
173 {
174 return disable_checking || n != delete_called;
175 }
176
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +0000177 bool checkLastNewSizeEq(std::size_t n) const
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000178 {
179 return disable_checking || n == last_new_size;
180 }
181
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +0000182 bool checkLastNewSizeNotEq(std::size_t n) const
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000183 {
184 return disable_checking || n != last_new_size;
185 }
186
187 bool checkOutstandingArrayNewEq(int n) const
188 {
189 return disable_checking || n == outstanding_array_new;
190 }
191
192 bool checkOutstandingArrayNewNotEq(int n) const
193 {
194 return disable_checking || n != outstanding_array_new;
195 }
196
197 bool checkNewArrayCalledEq(int n) const
198 {
199 return disable_checking || n == new_array_called;
200 }
201
202 bool checkNewArrayCalledNotEq(int n) const
203 {
204 return disable_checking || n != new_array_called;
205 }
206
207 bool checkDeleteArrayCalledEq(int n) const
208 {
209 return disable_checking || n == delete_array_called;
210 }
211
212 bool checkDeleteArrayCalledNotEq(int n) const
213 {
214 return disable_checking || n != delete_array_called;
215 }
216
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +0000217 bool checkLastNewArraySizeEq(std::size_t n) const
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000218 {
219 return disable_checking || n == last_new_array_size;
220 }
221
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +0000222 bool checkLastNewArraySizeNotEq(std::size_t n) const
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000223 {
224 return disable_checking || n != last_new_array_size;
225 }
226};
227
228#ifdef DISABLE_NEW_COUNT
229 const bool MemCounter::disable_checking = true;
230#else
231 const bool MemCounter::disable_checking = false;
232#endif
233
Eric Fiselier05092382017-06-21 21:42:50 +0000234inline MemCounter* getGlobalMemCounter() {
235 static MemCounter counter((MemCounter::MemCounterCtorArg_()));
236 return &counter;
237}
238
239MemCounter &globalMemCounter = *getGlobalMemCounter();
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000240
241#ifndef DISABLE_NEW_COUNT
Eric Fiselier3ca45662016-12-11 02:47:36 +0000242void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000243{
Eric Fiselier05092382017-06-21 21:42:50 +0000244 getGlobalMemCounter()->newCalled(s);
Eric Fiselier8ff74322016-06-22 03:46:32 +0000245 void* ret = std::malloc(s);
246 if (ret == nullptr)
247 detail::throw_bad_alloc_helper();
248 return ret;
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000249}
250
Eric Fiselier3ca45662016-12-11 02:47:36 +0000251void operator delete(void* p) TEST_NOEXCEPT
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000252{
Eric Fiselier05092382017-06-21 21:42:50 +0000253 getGlobalMemCounter()->deleteCalled(p);
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000254 std::free(p);
255}
256
257
Eric Fiselier3ca45662016-12-11 02:47:36 +0000258void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000259{
Eric Fiselier05092382017-06-21 21:42:50 +0000260 getGlobalMemCounter()->newArrayCalled(s);
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000261 return operator new(s);
262}
263
264
Eric Fiselier3ca45662016-12-11 02:47:36 +0000265void operator delete[](void* p) TEST_NOEXCEPT
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000266{
Eric Fiselier05092382017-06-21 21:42:50 +0000267 getGlobalMemCounter()->deleteArrayCalled(p);
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000268 operator delete(p);
269}
270
271#endif // DISABLE_NEW_COUNT
272
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000273
274struct DisableAllocationGuard {
275 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
276 {
277 // Don't re-disable if already disabled.
278 if (globalMemCounter.disable_allocations == true) m_disabled = false;
279 if (m_disabled) globalMemCounter.disableAllocations();
280 }
281
282 void release() {
283 if (m_disabled) globalMemCounter.enableAllocations();
284 m_disabled = false;
285 }
286
287 ~DisableAllocationGuard() {
288 release();
289 }
290
291private:
292 bool m_disabled;
293
294 DisableAllocationGuard(DisableAllocationGuard const&);
295 DisableAllocationGuard& operator=(DisableAllocationGuard const&);
296};
297
Eric Fiselierc7979582016-06-17 19:46:40 +0000298
299struct RequireAllocationGuard {
300 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
301 : m_req_alloc(RequireAtLeast),
302 m_new_count_on_init(globalMemCounter.new_called),
303 m_outstanding_new_on_init(globalMemCounter.outstanding_new),
304 m_exactly(false)
305 {
306 }
307
308 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
309 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
310
311 ~RequireAllocationGuard() {
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +0000312 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init)));
Eric Fiselierc7979582016-06-17 19:46:40 +0000313 std::size_t Expect = m_new_count_on_init + m_req_alloc;
Stephan T. Lavavejf41847c2016-12-06 01:14:43 +0000314 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) ||
315 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect))));
Eric Fiselierc7979582016-06-17 19:46:40 +0000316 }
317
318private:
319 std::size_t m_req_alloc;
320 const std::size_t m_new_count_on_init;
321 const std::size_t m_outstanding_new_on_init;
322 bool m_exactly;
323 RequireAllocationGuard(RequireAllocationGuard const&);
324 RequireAllocationGuard& operator=(RequireAllocationGuard const&);
325};
326
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000327#endif /* COUNT_NEW_HPP */