• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef COUNT_NEW_HPP
2 #define COUNT_NEW_HPP
3 
4 # include <cstdlib>
5 # include <cassert>
6 # include <new>
7 
8 #ifndef __has_feature
9 #  define __has_feature(x) 0
10 #endif
11 
12 #if  __has_feature(address_sanitizer) \
13   || __has_feature(memory_sanitizer) \
14   || __has_feature(thread_sanitizer)
15 #define DISABLE_NEW_COUNT
16 #endif
17 
18 class MemCounter
19 {
20 public:
21     // Make MemCounter super hard to accidentally construct or copy.
22     class MemCounterCtorArg_ {};
MemCounter(MemCounterCtorArg_)23     explicit MemCounter(MemCounterCtorArg_) { reset(); }
24 
25 private:
26     MemCounter(MemCounter const &);
27     MemCounter & operator=(MemCounter const &);
28 
29 public:
30     // All checks return true when disable_checking is enabled.
31     static const bool disable_checking;
32 
33     // Disallow any allocations from occurring. Useful for testing that
34     // code doesn't perform any allocations.
35     bool disable_allocations;
36 
37     int outstanding_new;
38     int new_called;
39     int delete_called;
40     int last_new_size;
41 
42     int outstanding_array_new;
43     int new_array_called;
44     int delete_array_called;
45     int last_new_array_size;
46 
47 public:
newCalled(std::size_t s)48     void newCalled(std::size_t s)
49     {
50         assert(disable_allocations == false);
51         assert(s);
52         ++new_called;
53         ++outstanding_new;
54         last_new_size = s;
55     }
56 
deleteCalled(void * p)57     void deleteCalled(void * p)
58     {
59         assert(p);
60         --outstanding_new;
61         ++delete_called;
62     }
63 
newArrayCalled(std::size_t s)64     void newArrayCalled(std::size_t s)
65     {
66         assert(disable_allocations == false);
67         assert(s);
68         ++outstanding_array_new;
69         ++new_array_called;
70         last_new_array_size = s;
71     }
72 
deleteArrayCalled(void * p)73     void deleteArrayCalled(void * p)
74     {
75         assert(p);
76         --outstanding_array_new;
77         ++delete_array_called;
78     }
79 
disableAllocations()80     void disableAllocations()
81     {
82         disable_allocations = true;
83     }
84 
enableAllocations()85     void enableAllocations()
86     {
87         disable_allocations = false;
88     }
89 
reset()90     void reset()
91     {
92         disable_allocations = false;
93 
94         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 
105 public:
checkOutstandingNewEq(int n) const106     bool checkOutstandingNewEq(int n) const
107     {
108         return disable_checking || n == outstanding_new;
109     }
110 
checkOutstandingNewNotEq(int n) const111     bool checkOutstandingNewNotEq(int n) const
112     {
113         return disable_checking || n != outstanding_new;
114     }
115 
checkNewCalledEq(int n) const116     bool checkNewCalledEq(int n) const
117     {
118         return disable_checking || n == new_called;
119     }
120 
checkNewCalledNotEq(int n) const121     bool checkNewCalledNotEq(int n) const
122     {
123         return disable_checking || n != new_called;
124     }
125 
checkDeleteCalledEq(int n) const126     bool checkDeleteCalledEq(int n) const
127     {
128         return disable_checking || n == delete_called;
129     }
130 
checkDeleteCalledNotEq(int n) const131     bool checkDeleteCalledNotEq(int n) const
132     {
133         return disable_checking || n != delete_called;
134     }
135 
checkLastNewSizeEq(int n) const136     bool checkLastNewSizeEq(int n) const
137     {
138         return disable_checking || n == last_new_size;
139     }
140 
checkLastNewSizeNotEq(int n) const141     bool checkLastNewSizeNotEq(int n) const
142     {
143         return disable_checking || n != last_new_size;
144     }
145 
checkOutstandingArrayNewEq(int n) const146     bool checkOutstandingArrayNewEq(int n) const
147     {
148         return disable_checking || n == outstanding_array_new;
149     }
150 
checkOutstandingArrayNewNotEq(int n) const151     bool checkOutstandingArrayNewNotEq(int n) const
152     {
153         return disable_checking || n != outstanding_array_new;
154     }
155 
checkNewArrayCalledEq(int n) const156     bool checkNewArrayCalledEq(int n) const
157     {
158         return disable_checking || n == new_array_called;
159     }
160 
checkNewArrayCalledNotEq(int n) const161     bool checkNewArrayCalledNotEq(int n) const
162     {
163         return disable_checking || n != new_array_called;
164     }
165 
checkDeleteArrayCalledEq(int n) const166     bool checkDeleteArrayCalledEq(int n) const
167     {
168         return disable_checking || n == delete_array_called;
169     }
170 
checkDeleteArrayCalledNotEq(int n) const171     bool checkDeleteArrayCalledNotEq(int n) const
172     {
173         return disable_checking || n != delete_array_called;
174     }
175 
checkLastNewArraySizeEq(int n) const176     bool checkLastNewArraySizeEq(int n) const
177     {
178         return disable_checking || n == last_new_array_size;
179     }
180 
checkLastNewArraySizeNotEq(int n) const181     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 
193 MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_()));
194 
195 #ifndef DISABLE_NEW_COUNT
operator new(std::size_t s)196 void* operator new(std::size_t s) throw(std::bad_alloc)
197 {
198     globalMemCounter.newCalled(s);
199     return std::malloc(s);
200 }
201 
operator delete(void * p)202 void  operator delete(void* p) throw()
203 {
204     globalMemCounter.deleteCalled(p);
205     std::free(p);
206 }
207 
208 
operator new[](std::size_t s)209 void* operator new[](std::size_t s) throw(std::bad_alloc)
210 {
211     globalMemCounter.newArrayCalled(s);
212     return operator new(s);
213 }
214 
215 
operator delete[](void * p)216 void operator delete[](void* p) throw()
217 {
218     globalMemCounter.deleteArrayCalled(p);
219     operator delete(p);
220 }
221 
222 #endif // DISABLE_NEW_COUNT
223 
224 
225 struct DisableAllocationGuard {
DisableAllocationGuardDisableAllocationGuard226     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 
releaseDisableAllocationGuard233     void release() {
234         if (m_disabled) globalMemCounter.enableAllocations();
235         m_disabled = false;
236     }
237 
~DisableAllocationGuardDisableAllocationGuard238     ~DisableAllocationGuard() {
239         release();
240     }
241 
242 private:
243     bool m_disabled;
244 
245     DisableAllocationGuard(DisableAllocationGuard const&);
246     DisableAllocationGuard& operator=(DisableAllocationGuard const&);
247 };
248 
249 #endif /* COUNT_NEW_HPP */
250