1 : #ifndef MALLOC_CHECK_H
2 : #define MALLOC_CHECK_H 1
3 :
4 : typedef struct Malloc_check_vals
5 : {
6 : void *ptr;
7 : size_t sz;
8 : const char *file;
9 : unsigned int line;
10 : } Malloc_check_vals;
11 :
12 : typedef struct Malloc_check_store
13 : {
14 : unsigned long mem_sz;
15 : unsigned long mem_num;
16 : unsigned long mem_fail_num;
17 : Malloc_check_vals *mem_vals;
18 : } Malloc_check_store;
19 :
20 : #ifndef MALLOC_CHECK__ATTR_USED
21 : #ifdef __GNUC__
22 : # define MALLOC_CHECK__ATTR_USED() __attribute__((__used__))
23 : #else
24 : # define MALLOC_CHECK__ATTR_USED() /* do nothing */
25 : #endif
26 : #endif
27 :
28 : #ifndef MALLOC_CHECK__ATTR_H
29 : #ifdef __GNUC__
30 : # define MALLOC_CHECK__ATTR_H() __attribute__((__visibility__("hidden")))
31 : #else
32 : # define MALLOC_CHECK__ATTR_H() /* do nothing */
33 : #endif
34 : #endif
35 :
36 : #ifndef MALLOC_CHECK__ATTR_MALLOC
37 : #ifdef __GNUC__
38 : # define MALLOC_CHECK__ATTR_MALLOC() __attribute__ ((__malloc__))
39 : #else
40 : # define MALLOC_CHECK__ATTR_MALLOC() /* do nothing */
41 : #endif
42 : #endif
43 :
44 : #ifndef MALLOC_CHECK_SUPPER_SCRUB /* never really call realloc() */
45 : #define MALLOC_CHECK_SUPPER_SCRUB 0
46 : #endif
47 :
48 : #ifndef MALLOC_CHECK_STORE
49 : #define MALLOC_CHECK_STORE malloc_check__app_store
50 : #endif
51 :
52 : /* NOTE: don't reset fail nums */
53 : #define MALLOC_CHECK_REINIT() \
54 : MALLOC_CHECK_STORE.mem_sz = 0; \
55 : MALLOC_CHECK_STORE.mem_num = 0; \
56 : MALLOC_CHECK_STORE.mem_vals = NULL
57 : #define MALLOC_CHECK_INIT() \
58 : MALLOC_CHECK_STORE.mem_fail_num = 0; \
59 : MALLOC_CHECK_REINIT()
60 :
61 : #ifndef USE_MALLOC_CHECK
62 : #ifndef NDEBUG
63 : # define USE_MALLOC_CHECK 1
64 : # else
65 : # define USE_MALLOC_CHECK 0
66 : # endif
67 : #endif
68 :
69 : #if !(USE_MALLOC_CHECK)
70 : #define MALLOC_CHECK_DECL() \
71 : static Malloc_check_store MALLOC_CHECK_STORE = {0, 0, 0, NULL}
72 :
73 : # define MALLOC_CHECK_MEM(x) (1)
74 : # define MALLOC_CHECK_SZ_MEM(x, y) (1)
75 : # define MALLOC_CHECK_EMPTY() /* nothing */
76 : # define MALLOC_CHECK_DEC() (0)
77 : # define MALLOC_CHECK_FAIL_IN(x) /* nothing */
78 : # define MALLOC_CHECK_SCRUB_PTR(x, y) /* nothing */
79 :
80 : # define malloc_check_malloc(x, F, L) malloc(x)
81 : # define malloc_check_calloc(x, y, F, L) calloc(x, y)
82 : # define malloc_check_realloc(x, y, F, L) realloc(x, y)
83 : # define malloc_check_free(x) free(x)
84 : #else
85 :
86 : #include <stdio.h>
87 :
88 : extern Malloc_check_store MALLOC_CHECK__ATTR_H() MALLOC_CHECK_STORE;
89 :
90 : #define MALLOC_CHECK_DECL() \
91 : Malloc_check_store MALLOC_CHECK_STORE = {0, 0, 0, NULL}
92 :
93 : # define MALLOC_CHECK_MEM(x) malloc_check_mem(x)
94 : # define MALLOC_CHECK_SZ_MEM(x, y) malloc_check_sz_mem(x, y)
95 : # define MALLOC_CHECK_EMPTY() malloc_check_empty()
96 : # define MALLOC_CHECK_DEC() \
97 : (MALLOC_CHECK_STORE.mem_fail_num && !--MALLOC_CHECK_STORE.mem_fail_num)
98 : # define MALLOC_CHECK_FAIL_IN(x) MALLOC_CHECK_STORE.mem_fail_num = (x)
99 : # define MALLOC_CHECK_SCRUB_PTR(x, y) memset(x, 0xa5, y)
100 :
101 : #ifndef MALLOC_CHECK_PRINT
102 : #define MALLOC_CHECK_PRINT 1
103 : #endif
104 :
105 : #ifndef SWAP_TYPE
106 : #define SWAP_TYPE(x, y, type) do { \
107 : type internal_local_tmp = (x); \
108 : (x) = (y); \
109 : (y) = internal_local_tmp; \
110 : } while (FALSE)
111 : #endif
112 :
113 : static void malloc_check_alloc(void)
114 : MALLOC_CHECK__ATTR_USED();
115 : static unsigned int malloc_check_mem(const void *)
116 : MALLOC_CHECK__ATTR_USED();
117 : static unsigned int malloc_check_sz_mem(const void *, size_t)
118 : MALLOC_CHECK__ATTR_USED();
119 : static void *malloc_check_malloc(size_t, const char *, unsigned int)
120 : MALLOC_CHECK__ATTR_MALLOC() MALLOC_CHECK__ATTR_USED();
121 : static void *malloc_check_calloc(size_t, size_t, const char *, unsigned int)
122 : MALLOC_CHECK__ATTR_MALLOC() MALLOC_CHECK__ATTR_USED();
123 : static void malloc_check_free(void *)
124 : MALLOC_CHECK__ATTR_USED();
125 : static void *malloc_check_realloc(void *, size_t,
126 : const char *, unsigned int)
127 : MALLOC_CHECK__ATTR_MALLOC() MALLOC_CHECK__ATTR_USED();
128 : static void malloc_check_empty(void)
129 : MALLOC_CHECK__ATTR_USED();
130 :
131 : static void malloc_check_alloc(void)
132 53743 : {
133 53743 : size_t sz = MALLOC_CHECK_STORE.mem_sz;
134 :
135 53743 : ++MALLOC_CHECK_STORE.mem_num;
136 :
137 53743 : if (!MALLOC_CHECK_STORE.mem_sz)
138 : {
139 176 : sz = 8;
140 176 : MALLOC_CHECK_STORE.mem_vals = malloc(sizeof(Malloc_check_vals) * sz);
141 : }
142 53567 : else if (MALLOC_CHECK_STORE.mem_num > MALLOC_CHECK_STORE.mem_sz)
143 : {
144 54 : sz *= 2;
145 54 : MALLOC_CHECK_STORE.mem_vals = realloc(MALLOC_CHECK_STORE.mem_vals,
146 : sizeof(Malloc_check_vals) * sz);
147 : }
148 53743 : ASSERT(MALLOC_CHECK_STORE.mem_num <= sz);
149 53743 : ASSERT(MALLOC_CHECK_STORE.mem_vals);
150 :
151 53743 : MALLOC_CHECK_STORE.mem_sz = sz;
152 53743 : }
153 :
154 : static unsigned int malloc_check_mem(const void *ptr)
155 203602 : {
156 203602 : unsigned int scan = 0;
157 :
158 203602 : ASSERT(MALLOC_CHECK_STORE.mem_num);
159 :
160 4970614 : while (MALLOC_CHECK_STORE.mem_vals[scan].ptr &&
161 : (MALLOC_CHECK_STORE.mem_vals[scan].ptr != ptr))
162 4767012 : ++scan;
163 :
164 203602 : ASSERT(MALLOC_CHECK_STORE.mem_vals[scan].ptr);
165 :
166 203602 : return (scan);
167 : }
168 :
169 : static unsigned int malloc_check_sz_mem(const void *ptr, size_t sz)
170 121336 : {
171 121336 : unsigned int scan = malloc_check_mem(ptr);
172 :
173 121336 : ASSERT(MALLOC_CHECK_STORE.mem_vals[scan].sz == sz);
174 :
175 121336 : return (scan);
176 : }
177 :
178 : static void *malloc_check_malloc(size_t sz, const char *file, unsigned int line)
179 53743 : {
180 53743 : void *ret = NULL;
181 :
182 53743 : if (MALLOC_CHECK_DEC())
183 0 : return (NULL);
184 :
185 53743 : malloc_check_alloc();
186 :
187 53743 : ASSERT(sz);
188 :
189 53743 : ret = malloc(sz);
190 53743 : ASSERT_RET(ret, NULL);
191 :
192 53743 : MALLOC_CHECK_SCRUB_PTR(ret, sz);
193 :
194 53743 : MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].ptr = ret;
195 53743 : MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].sz = sz;
196 53743 : MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].file = file;
197 53743 : MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].line = line;
198 :
199 53743 : return (ret);
200 : }
201 :
202 : static void *malloc_check_calloc(size_t num, size_t sz,
203 : const char *file, unsigned int line)
204 32 : {
205 32 : size_t real_sz = num * sz;
206 32 : void *ret = NULL;
207 :
208 32 : if ((num != 0) && ((real_sz / sz) != num))
209 0 : return (NULL);
210 32 : if (!(ret = malloc_check_malloc(real_sz, file, line)))
211 0 : return (NULL);
212 :
213 32 : memset(ret, 0, real_sz);
214 32 : return (ret);
215 : }
216 :
217 : static void malloc_check_free(void *ptr)
218 71639 : {
219 71639 : if (ptr)
220 : {
221 53713 : unsigned int scan = malloc_check_mem(ptr);
222 53713 : size_t sz = 0;
223 :
224 53713 : ASSERT(MALLOC_CHECK_STORE.mem_num > 0);
225 53713 : --MALLOC_CHECK_STORE.mem_num;
226 :
227 53713 : sz = MALLOC_CHECK_STORE.mem_vals[scan].sz;
228 53713 : if (scan != MALLOC_CHECK_STORE.mem_num)
229 : {
230 7076 : unsigned int num = MALLOC_CHECK_STORE.mem_num;
231 7076 : Malloc_check_vals *val1 = &MALLOC_CHECK_STORE.mem_vals[scan];
232 7076 : Malloc_check_vals *val2 = &MALLOC_CHECK_STORE.mem_vals[num];
233 :
234 7076 : SWAP_TYPE(val1->ptr, val2->ptr, void *);
235 7076 : SWAP_TYPE(val1->sz, val2->sz, size_t);
236 7076 : SWAP_TYPE(val1->file, val2->file, const char *);
237 7076 : SWAP_TYPE(val1->line, val2->line, unsigned int);
238 : }
239 53713 : MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num].ptr = NULL;
240 53713 : MALLOC_CHECK_SCRUB_PTR(ptr, sz);
241 53713 : free(ptr);
242 : }
243 71639 : }
244 :
245 : static void *malloc_check_realloc(void *ptr, size_t sz,
246 : const char *file, unsigned int line)
247 28553 : {
248 28553 : void *ret = NULL;
249 28553 : unsigned int scan = malloc_check_mem(ptr);
250 :
251 28553 : ASSERT(ptr && sz);
252 :
253 : if (MALLOC_CHECK_SUPPER_SCRUB)
254 : {
255 : if (!(ret = malloc_check_malloc(sz, file, line)))
256 : return (NULL);
257 :
258 : if (sz >= MALLOC_CHECK_STORE.mem_vals[scan].sz)
259 : sz = MALLOC_CHECK_STORE.mem_vals[scan].sz;
260 : if (sz)
261 : memcpy(ret, ptr, sz);
262 :
263 : malloc_check_free(ptr);
264 :
265 : return (ret);
266 : }
267 :
268 28553 : if (MALLOC_CHECK_DEC())
269 0 : return (NULL);
270 :
271 28553 : ret = realloc(ptr, sz);
272 28553 : ASSERT_RET(ret, NULL);
273 :
274 : /* note we can't scrub ... :( */
275 28553 : MALLOC_CHECK_STORE.mem_vals[scan].ptr = ret;
276 28553 : MALLOC_CHECK_STORE.mem_vals[scan].sz = sz;
277 28553 : MALLOC_CHECK_STORE.mem_vals[scan].file = file;
278 28553 : MALLOC_CHECK_STORE.mem_vals[scan].line = line;
279 :
280 28553 : return (ret);
281 : }
282 :
283 : static void malloc_check_empty(void)
284 166 : {
285 166 : if (MALLOC_CHECK_PRINT && MALLOC_CHECK_STORE.mem_num)
286 : {
287 0 : unsigned int scan = 0;
288 :
289 0 : while (MALLOC_CHECK_STORE.mem_vals[scan].ptr)
290 : {
291 0 : fprintf(stderr, " FAILED MEM CHECK EMPTY: ptr %p, sz %zu, from %u:%s\n",
292 : MALLOC_CHECK_STORE.mem_vals[scan].ptr,
293 : MALLOC_CHECK_STORE.mem_vals[scan].sz,
294 : MALLOC_CHECK_STORE.mem_vals[scan].line,
295 : MALLOC_CHECK_STORE.mem_vals[scan].file);
296 0 : ++scan;
297 : }
298 : }
299 166 : ASSERT(!MALLOC_CHECK_STORE.mem_num);
300 166 : }
301 : #endif
302 :
303 : #endif
|