blob: 580e67505df5e400cce2f6edd2e3ddc418a7c081 [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 Fiselierf2f2a632016-06-14 21:31:42 +000019#if TEST_HAS_FEATURE(address_sanitizer) \
20 || TEST_HAS_FEATURE(memory_sanitizer) \
21 || TEST_HAS_FEATURE(thread_sanitizer)
Eric Fiselier2cbc6542014-12-22 22:38:59 +000022#define DISABLE_NEW_COUNT
23#endif
24
Eric Fiselier8ff74322016-06-22 03:46:32 +000025namespace detail
26{
27 inline void throw_bad_alloc_helper() {
28#ifndef TEST_HAS_NO_EXCEPTIONS
29 throw std::bad_alloc();
30#else
31 std::abort();
32#endif
33 }
34}
35
Eric Fiselier2cbc6542014-12-22 22:38:59 +000036class MemCounter
37{
38public:
39 // Make MemCounter super hard to accidentally construct or copy.
40 class MemCounterCtorArg_ {};
Eric Fiselier85b788c2015-02-10 15:17:46 +000041 explicit MemCounter(MemCounterCtorArg_) { reset(); }
Eric Fiselier2cbc6542014-12-22 22:38:59 +000042
43private:
44 MemCounter(MemCounter const &);
45 MemCounter & operator=(MemCounter const &);
46
47public:
48 // All checks return true when disable_checking is enabled.
49 static const bool disable_checking;
50
Eric Fiselier3461dbc2015-07-31 02:24:58 +000051 // Disallow any allocations from occurring. Useful for testing that
52 // code doesn't perform any allocations.
53 bool disable_allocations;
54
Eric Fiselier8ff74322016-06-22 03:46:32 +000055 // number of allocations to throw after. Default (unsigned)-1. If
56 // throw_after has the default value it will never be decremented.
57 static const unsigned never_throw_value = static_cast<unsigned>(-1);
58 unsigned throw_after;
59
Eric Fiselier85b788c2015-02-10 15:17:46 +000060 int outstanding_new;
61 int new_called;
62 int delete_called;
63 int last_new_size;
Eric Fiselier2cbc6542014-12-22 22:38:59 +000064
Eric Fiselier85b788c2015-02-10 15:17:46 +000065 int outstanding_array_new;
66 int new_array_called;
67 int delete_array_called;
68 int last_new_array_size;
Eric Fiselier2cbc6542014-12-22 22:38:59 +000069
70public:
71 void newCalled(std::size_t s)
72 {
Eric Fiselier3461dbc2015-07-31 02:24:58 +000073 assert(disable_allocations == false);
Eric Fiselier2cbc6542014-12-22 22:38:59 +000074 assert(s);
Eric Fiselier8ff74322016-06-22 03:46:32 +000075 if (throw_after == 0) {
76 throw_after = never_throw_value;
77 detail::throw_bad_alloc_helper();
78 } else if (throw_after != never_throw_value) {
79 --throw_after;
80 }
Eric Fiselier2cbc6542014-12-22 22:38:59 +000081 ++new_called;
82 ++outstanding_new;
83 last_new_size = s;
84 }
85
86 void deleteCalled(void * p)
87 {
88 assert(p);
89 --outstanding_new;
90 ++delete_called;
91 }
92
93 void newArrayCalled(std::size_t s)
94 {
Eric Fiselier3461dbc2015-07-31 02:24:58 +000095 assert(disable_allocations == false);
Eric Fiselier2cbc6542014-12-22 22:38:59 +000096 assert(s);
Eric Fiselier8ff74322016-06-22 03:46:32 +000097 if (throw_after == 0) {
98 throw_after = never_throw_value;
99 detail::throw_bad_alloc_helper();
100 } else {
101 // don't decrement throw_after here. newCalled will end up doing that.
102 }
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000103 ++outstanding_array_new;
104 ++new_array_called;
105 last_new_array_size = s;
106 }
107
108 void deleteArrayCalled(void * p)
109 {
110 assert(p);
111 --outstanding_array_new;
112 ++delete_array_called;
113 }
114
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000115 void disableAllocations()
116 {
117 disable_allocations = true;
118 }
119
120 void enableAllocations()
121 {
122 disable_allocations = false;
123 }
124
Eric Fiselier8ff74322016-06-22 03:46:32 +0000125
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000126 void reset()
127 {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000128 disable_allocations = false;
Eric Fiselier8ff74322016-06-22 03:46:32 +0000129 throw_after = never_throw_value;
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000130
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000131 outstanding_new = 0;
132 new_called = 0;
133 delete_called = 0;
134 last_new_size = 0;
135
136 outstanding_array_new = 0;
137 new_array_called = 0;
138 delete_array_called = 0;
139 last_new_array_size = 0;
140 }
141
142public:
143 bool checkOutstandingNewEq(int n) const
144 {
145 return disable_checking || n == outstanding_new;
146 }
147
148 bool checkOutstandingNewNotEq(int n) const
149 {
150 return disable_checking || n != outstanding_new;
151 }
152
153 bool checkNewCalledEq(int n) const
154 {
155 return disable_checking || n == new_called;
156 }
157
158 bool checkNewCalledNotEq(int n) const
159 {
160 return disable_checking || n != new_called;
161 }
162
Eric Fiselierc7979582016-06-17 19:46:40 +0000163 bool checkNewCalledGreaterThan(int n) const
164 {
165 return disable_checking || new_called > n;
166 }
167
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000168 bool checkDeleteCalledEq(int n) const
169 {
170 return disable_checking || n == delete_called;
171 }
172
173 bool checkDeleteCalledNotEq(int n) const
174 {
175 return disable_checking || n != delete_called;
176 }
177
178 bool checkLastNewSizeEq(int n) const
179 {
180 return disable_checking || n == last_new_size;
181 }
182
183 bool checkLastNewSizeNotEq(int n) const
184 {
185 return disable_checking || n != last_new_size;
186 }
187
188 bool checkOutstandingArrayNewEq(int n) const
189 {
190 return disable_checking || n == outstanding_array_new;
191 }
192
193 bool checkOutstandingArrayNewNotEq(int n) const
194 {
195 return disable_checking || n != outstanding_array_new;
196 }
197
198 bool checkNewArrayCalledEq(int n) const
199 {
200 return disable_checking || n == new_array_called;
201 }
202
203 bool checkNewArrayCalledNotEq(int n) const
204 {
205 return disable_checking || n != new_array_called;
206 }
207
208 bool checkDeleteArrayCalledEq(int n) const
209 {
210 return disable_checking || n == delete_array_called;
211 }
212
213 bool checkDeleteArrayCalledNotEq(int n) const
214 {
215 return disable_checking || n != delete_array_called;
216 }
217
218 bool checkLastNewArraySizeEq(int n) const
219 {
220 return disable_checking || n == last_new_array_size;
221 }
222
223 bool checkLastNewArraySizeNotEq(int n) const
224 {
225 return disable_checking || n != last_new_array_size;
226 }
227};
228
229#ifdef DISABLE_NEW_COUNT
230 const bool MemCounter::disable_checking = true;
231#else
232 const bool MemCounter::disable_checking = false;
233#endif
234
235MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_()));
236
237#ifndef DISABLE_NEW_COUNT
238void* operator new(std::size_t s) throw(std::bad_alloc)
239{
240 globalMemCounter.newCalled(s);
Eric Fiselier8ff74322016-06-22 03:46:32 +0000241 void* ret = std::malloc(s);
242 if (ret == nullptr)
243 detail::throw_bad_alloc_helper();
244 return ret;
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000245}
246
247void operator delete(void* p) throw()
248{
249 globalMemCounter.deleteCalled(p);
250 std::free(p);
251}
252
253
254void* operator new[](std::size_t s) throw(std::bad_alloc)
255{
256 globalMemCounter.newArrayCalled(s);
257 return operator new(s);
258}
259
260
261void operator delete[](void* p) throw()
262{
263 globalMemCounter.deleteArrayCalled(p);
264 operator delete(p);
265}
266
267#endif // DISABLE_NEW_COUNT
268
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000269
270struct DisableAllocationGuard {
271 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
272 {
273 // Don't re-disable if already disabled.
274 if (globalMemCounter.disable_allocations == true) m_disabled = false;
275 if (m_disabled) globalMemCounter.disableAllocations();
276 }
277
278 void release() {
279 if (m_disabled) globalMemCounter.enableAllocations();
280 m_disabled = false;
281 }
282
283 ~DisableAllocationGuard() {
284 release();
285 }
286
287private:
288 bool m_disabled;
289
290 DisableAllocationGuard(DisableAllocationGuard const&);
291 DisableAllocationGuard& operator=(DisableAllocationGuard const&);
292};
293
Eric Fiselierc7979582016-06-17 19:46:40 +0000294
295struct RequireAllocationGuard {
296 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
297 : m_req_alloc(RequireAtLeast),
298 m_new_count_on_init(globalMemCounter.new_called),
299 m_outstanding_new_on_init(globalMemCounter.outstanding_new),
300 m_exactly(false)
301 {
302 }
303
304 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
305 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
306
307 ~RequireAllocationGuard() {
308 assert(globalMemCounter.checkOutstandingNewEq(m_outstanding_new_on_init));
309 std::size_t Expect = m_new_count_on_init + m_req_alloc;
310 assert(globalMemCounter.checkNewCalledEq(Expect) ||
311 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(Expect)));
312 }
313
314private:
315 std::size_t m_req_alloc;
316 const std::size_t m_new_count_on_init;
317 const std::size_t m_outstanding_new_on_init;
318 bool m_exactly;
319 RequireAllocationGuard(RequireAllocationGuard const&);
320 RequireAllocationGuard& operator=(RequireAllocationGuard const&);
321};
322
Eric Fiselier2cbc6542014-12-22 22:38:59 +0000323#endif /* COUNT_NEW_HPP */