blob: 57aca7def33526bf279d475471c83b3752a61dfc [file] [log] [blame]
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +00001#ifndef COUNT_NEW_HPP
2#define COUNT_NEW_HPP
3
4# include <cstdlib>
5# include <cassert>
6# include <new>
7
Eric Fiseliera4449da2015-01-27 23:03:38 +00008#ifndef __has_feature
Eric Fiselierdb5d6af2015-01-27 23:05:41 +00009# define __has_feature(x) 0
Eric Fiseliera4449da2015-01-27 23:03:38 +000010#endif
11
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000012#if __has_feature(address_sanitizer) \
Eric Fiselier07a4bec2015-03-10 20:46:04 +000013 || __has_feature(memory_sanitizer) \
14 || __has_feature(thread_sanitizer)
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000015#define DISABLE_NEW_COUNT
16#endif
17
18class MemCounter
19{
20public:
21 // Make MemCounter super hard to accidentally construct or copy.
22 class MemCounterCtorArg_ {};
Eric Fiselierf17cecb2015-02-10 15:17:46 +000023 explicit MemCounter(MemCounterCtorArg_) { reset(); }
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000024
25private:
26 MemCounter(MemCounter const &);
27 MemCounter & operator=(MemCounter const &);
28
29public:
30 // All checks return true when disable_checking is enabled.
31 static const bool disable_checking;
32
Eric Fiselier7175a072015-07-31 02:24:58 +000033 // Disallow any allocations from occurring. Useful for testing that
34 // code doesn't perform any allocations.
35 bool disable_allocations;
36
Eric Fiselierf17cecb2015-02-10 15:17:46 +000037 int outstanding_new;
38 int new_called;
39 int delete_called;
40 int last_new_size;
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000041
Eric Fiselierf17cecb2015-02-10 15:17:46 +000042 int outstanding_array_new;
43 int new_array_called;
44 int delete_array_called;
45 int last_new_array_size;
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000046
47public:
48 void newCalled(std::size_t s)
49 {
Eric Fiselier7175a072015-07-31 02:24:58 +000050 assert(disable_allocations == false);
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000051 assert(s);
52 ++new_called;
53 ++outstanding_new;
54 last_new_size = s;
55 }
56
57 void deleteCalled(void * p)
58 {
59 assert(p);
60 --outstanding_new;
61 ++delete_called;
62 }
63
64 void newArrayCalled(std::size_t s)
65 {
Eric Fiselier7175a072015-07-31 02:24:58 +000066 assert(disable_allocations == false);
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000067 assert(s);
68 ++outstanding_array_new;
69 ++new_array_called;
70 last_new_array_size = s;
71 }
72
73 void deleteArrayCalled(void * p)
74 {
75 assert(p);
76 --outstanding_array_new;
77 ++delete_array_called;
78 }
79
Eric Fiselier7175a072015-07-31 02:24:58 +000080 void disableAllocations()
81 {
82 disable_allocations = true;
83 }
84
85 void enableAllocations()
86 {
87 disable_allocations = false;
88 }
89
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000090 void reset()
91 {
Eric Fiselier7175a072015-07-31 02:24:58 +000092 disable_allocations = false;
93
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +000094 outstanding_new = 0;
95 new_called = 0;
96 delete_called = 0;
97 last_new_size = 0;
98
99 outstanding_array_new = 0;
100 new_array_called = 0;
101 delete_array_called = 0;
102 last_new_array_size = 0;
103 }
104
105public:
106 bool checkOutstandingNewEq(int n) const
107 {
108 return disable_checking || n == outstanding_new;
109 }
110
111 bool checkOutstandingNewNotEq(int n) const
112 {
113 return disable_checking || n != outstanding_new;
114 }
115
116 bool checkNewCalledEq(int n) const
117 {
118 return disable_checking || n == new_called;
119 }
120
121 bool checkNewCalledNotEq(int n) const
122 {
123 return disable_checking || n != new_called;
124 }
125
126 bool checkDeleteCalledEq(int n) const
127 {
128 return disable_checking || n == delete_called;
129 }
130
131 bool checkDeleteCalledNotEq(int n) const
132 {
133 return disable_checking || n != delete_called;
134 }
135
136 bool checkLastNewSizeEq(int n) const
137 {
138 return disable_checking || n == last_new_size;
139 }
140
141 bool checkLastNewSizeNotEq(int n) const
142 {
143 return disable_checking || n != last_new_size;
144 }
145
146 bool checkOutstandingArrayNewEq(int n) const
147 {
148 return disable_checking || n == outstanding_array_new;
149 }
150
151 bool checkOutstandingArrayNewNotEq(int n) const
152 {
153 return disable_checking || n != outstanding_array_new;
154 }
155
156 bool checkNewArrayCalledEq(int n) const
157 {
158 return disable_checking || n == new_array_called;
159 }
160
161 bool checkNewArrayCalledNotEq(int n) const
162 {
163 return disable_checking || n != new_array_called;
164 }
165
166 bool checkDeleteArrayCalledEq(int n) const
167 {
168 return disable_checking || n == delete_array_called;
169 }
170
171 bool checkDeleteArrayCalledNotEq(int n) const
172 {
173 return disable_checking || n != delete_array_called;
174 }
175
176 bool checkLastNewArraySizeEq(int n) const
177 {
178 return disable_checking || n == last_new_array_size;
179 }
180
181 bool checkLastNewArraySizeNotEq(int n) const
182 {
183 return disable_checking || n != last_new_array_size;
184 }
185};
186
187#ifdef DISABLE_NEW_COUNT
188 const bool MemCounter::disable_checking = true;
189#else
190 const bool MemCounter::disable_checking = false;
191#endif
192
193MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_()));
194
195#ifndef DISABLE_NEW_COUNT
196void* operator new(std::size_t s) throw(std::bad_alloc)
197{
198 globalMemCounter.newCalled(s);
199 return std::malloc(s);
200}
201
202void operator delete(void* p) throw()
203{
204 globalMemCounter.deleteCalled(p);
205 std::free(p);
206}
207
208
209void* operator new[](std::size_t s) throw(std::bad_alloc)
210{
211 globalMemCounter.newArrayCalled(s);
212 return operator new(s);
213}
214
215
216void operator delete[](void* p) throw()
217{
218 globalMemCounter.deleteArrayCalled(p);
219 operator delete(p);
220}
221
222#endif // DISABLE_NEW_COUNT
223
Eric Fiselier7175a072015-07-31 02:24:58 +0000224
225struct DisableAllocationGuard {
226 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
227 {
228 // Don't re-disable if already disabled.
229 if (globalMemCounter.disable_allocations == true) m_disabled = false;
230 if (m_disabled) globalMemCounter.disableAllocations();
231 }
232
233 void release() {
234 if (m_disabled) globalMemCounter.enableAllocations();
235 m_disabled = false;
236 }
237
238 ~DisableAllocationGuard() {
239 release();
240 }
241
242private:
243 bool m_disabled;
244
245 DisableAllocationGuard(DisableAllocationGuard const&);
246 DisableAllocationGuard& operator=(DisableAllocationGuard const&);
247};
248
Eric Fiselier4eb5b6d2014-12-22 22:38:59 +0000249#endif /* COUNT_NEW_HPP */