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 #define DISABLE_NEW_COUNT
15 #endif
16 
17 class MemCounter
18 {
19 public:
20     // Make MemCounter super hard to accidentally construct or copy.
21     class MemCounterCtorArg_ {};
MemCounter(MemCounterCtorArg_)22     explicit MemCounter(MemCounterCtorArg_) { reset(); }
23 
24 private:
25     MemCounter(MemCounter const &);
26     MemCounter & operator=(MemCounter const &);
27 
28 public:
29     // All checks return true when disable_checking is enabled.
30     static const bool disable_checking;
31 
32     int outstanding_new;
33     int new_called;
34     int delete_called;
35     int last_new_size;
36 
37     int outstanding_array_new;
38     int new_array_called;
39     int delete_array_called;
40     int last_new_array_size;
41 
42 public:
newCalled(std::size_t s)43     void newCalled(std::size_t s)
44     {
45         assert(s);
46         ++new_called;
47         ++outstanding_new;
48         last_new_size = s;
49     }
50 
deleteCalled(void * p)51     void deleteCalled(void * p)
52     {
53         assert(p);
54         --outstanding_new;
55         ++delete_called;
56     }
57 
newArrayCalled(std::size_t s)58     void newArrayCalled(std::size_t s)
59     {
60         assert(s);
61         ++outstanding_array_new;
62         ++new_array_called;
63         last_new_array_size = s;
64     }
65 
deleteArrayCalled(void * p)66     void deleteArrayCalled(void * p)
67     {
68         assert(p);
69         --outstanding_array_new;
70         ++delete_array_called;
71     }
72 
reset()73     void reset()
74     {
75         outstanding_new = 0;
76         new_called = 0;
77         delete_called = 0;
78         last_new_size = 0;
79 
80         outstanding_array_new = 0;
81         new_array_called = 0;
82         delete_array_called = 0;
83         last_new_array_size = 0;
84     }
85 
86 public:
checkOutstandingNewEq(int n) const87     bool checkOutstandingNewEq(int n) const
88     {
89         return disable_checking || n == outstanding_new;
90     }
91 
checkOutstandingNewNotEq(int n) const92     bool checkOutstandingNewNotEq(int n) const
93     {
94         return disable_checking || n != outstanding_new;
95     }
96 
checkNewCalledEq(int n) const97     bool checkNewCalledEq(int n) const
98     {
99         return disable_checking || n == new_called;
100     }
101 
checkNewCalledNotEq(int n) const102     bool checkNewCalledNotEq(int n) const
103     {
104         return disable_checking || n != new_called;
105     }
106 
checkDeleteCalledEq(int n) const107     bool checkDeleteCalledEq(int n) const
108     {
109         return disable_checking || n == delete_called;
110     }
111 
checkDeleteCalledNotEq(int n) const112     bool checkDeleteCalledNotEq(int n) const
113     {
114         return disable_checking || n != delete_called;
115     }
116 
checkLastNewSizeEq(int n) const117     bool checkLastNewSizeEq(int n) const
118     {
119         return disable_checking || n == last_new_size;
120     }
121 
checkLastNewSizeNotEq(int n) const122     bool checkLastNewSizeNotEq(int n) const
123     {
124         return disable_checking || n != last_new_size;
125     }
126 
checkOutstandingArrayNewEq(int n) const127     bool checkOutstandingArrayNewEq(int n) const
128     {
129         return disable_checking || n == outstanding_array_new;
130     }
131 
checkOutstandingArrayNewNotEq(int n) const132     bool checkOutstandingArrayNewNotEq(int n) const
133     {
134         return disable_checking || n != outstanding_array_new;
135     }
136 
checkNewArrayCalledEq(int n) const137     bool checkNewArrayCalledEq(int n) const
138     {
139         return disable_checking || n == new_array_called;
140     }
141 
checkNewArrayCalledNotEq(int n) const142     bool checkNewArrayCalledNotEq(int n) const
143     {
144         return disable_checking || n != new_array_called;
145     }
146 
checkDeleteArrayCalledEq(int n) const147     bool checkDeleteArrayCalledEq(int n) const
148     {
149         return disable_checking || n == delete_array_called;
150     }
151 
checkDeleteArrayCalledNotEq(int n) const152     bool checkDeleteArrayCalledNotEq(int n) const
153     {
154         return disable_checking || n != delete_array_called;
155     }
156 
checkLastNewArraySizeEq(int n) const157     bool checkLastNewArraySizeEq(int n) const
158     {
159         return disable_checking || n == last_new_array_size;
160     }
161 
checkLastNewArraySizeNotEq(int n) const162     bool checkLastNewArraySizeNotEq(int n) const
163     {
164         return disable_checking || n != last_new_array_size;
165     }
166 };
167 
168 #ifdef DISABLE_NEW_COUNT
169   const bool MemCounter::disable_checking = true;
170 #else
171   const bool MemCounter::disable_checking = false;
172 #endif
173 
174 MemCounter globalMemCounter((MemCounter::MemCounterCtorArg_()));
175 
176 #ifndef DISABLE_NEW_COUNT
operator new(std::size_t s)177 void* operator new(std::size_t s) throw(std::bad_alloc)
178 {
179     globalMemCounter.newCalled(s);
180     return std::malloc(s);
181 }
182 
operator delete(void * p)183 void  operator delete(void* p) throw()
184 {
185     globalMemCounter.deleteCalled(p);
186     std::free(p);
187 }
188 
189 
operator new[](std::size_t s)190 void* operator new[](std::size_t s) throw(std::bad_alloc)
191 {
192     globalMemCounter.newArrayCalled(s);
193     return operator new(s);
194 }
195 
196 
operator delete[](void * p)197 void operator delete[](void* p) throw()
198 {
199     globalMemCounter.deleteArrayCalled(p);
200     operator delete(p);
201 }
202 
203 #endif // DISABLE_NEW_COUNT
204 
205 #endif /* COUNT_NEW_HPP */
206