1 : /* Copyright (c) 2007 James Antill -- See LICENSE file for terms. */
2 :
3 : #ifndef USTR_MAIN_H
4 : #error " You should have already included ustr-main.h, or just include ustr.h."
5 : #endif
6 :
7 : /* not sure of the version */
8 : #if defined(__GNUC__) && !defined(__STRICT_ANSI__) && (__GNUC__ > 3) && \
9 : USTR_CONF_COMPILE_USE_ATTRIBUTES
10 : # define USTR__COMPILE_ATTR_H() __attribute__((visibility("hidden")))
11 : #else
12 : # define USTR__COMPILE_ATTR_H()
13 : #endif
14 :
15 : #include <stdarg.h> /* va_list for va_arg() functionality */
16 :
17 : /* second set of defaults... *sigh* */
18 : struct Ustr_opts USTR__COMPILE_ATTR_H() ustr__opts[1] = {
19 : {1, /* ref bytes */
20 : {ustr__cntl_mc_setup_malloc, /* malloc be called first */
21 : realloc,
22 : free}, /* Ustr_cntl_mem */
23 : {vsnprintf, vsnprintf}, /* fmt */
24 : USTR_FALSE, /* has_size */
25 : USTR_FALSE, /* exact_bytes */
26 : USTR_FALSE, /* scrub on malloc */
27 : USTR_FALSE, /* scrub on free */
28 : USTR_FALSE /* scrub on realloc */
29 : }};
30 :
31 : /* not namespaced because this must be in a C-file. */
32 : #ifndef USE_MALLOC_CHECK
33 : #define USE_MALLOC_CHECK 1
34 : #endif
35 : #define MALLOC_CHECK_API_M_SCRUB ustr__opts->mc_m_scrub
36 : #define MALLOC_CHECK_API_F_SCRUB ustr__opts->mc_f_scrub
37 : #define MALLOC_CHECK_API_R_SCRUB ustr__opts->mc_r_scrub
38 : #define MALLOC_CHECK_SCOPE_EXTERN 0
39 : #include "malloc-check.h"
40 :
41 : MALLOC_CHECK_DECL();
42 :
43 : typedef struct Ustr__cntl_mc_ptrs
44 : {
45 : const char *file;
46 : unsigned int line;
47 : const char *func;
48 : } Ustr__cntl_mc_ptrs;
49 : Ustr__cntl_mc_ptrs USTR__COMPILE_ATTR_H() *ustr__cntl_mc_ptr = 0;
50 : size_t USTR__COMPILE_ATTR_H() ustr__cntl_mc_num = 0;
51 : size_t USTR__COMPILE_ATTR_H() ustr__cntl_mc_sz = 0;
52 :
53 : #define USTR__STREQ(x, y) !strcmp(x, y)
54 :
55 : USTR_CONF_i_PROTO int ustr__cntl_mc_setup_env2bool(const char *key, int def)
56 10 : {
57 10 : const char *ptr = getenv(key);
58 :
59 10 : if (!ptr) return (!!def);
60 :
61 10 : if (USTR__STREQ(ptr, "1")) return (USTR_TRUE);
62 10 : if (USTR__STREQ(ptr, "on")) return (USTR_TRUE);
63 10 : if (USTR__STREQ(ptr, "yes")) return (USTR_TRUE);
64 :
65 8 : if (USTR__STREQ(ptr, "0")) return (USTR_FALSE);
66 8 : if (USTR__STREQ(ptr, "off")) return (USTR_FALSE);
67 8 : if (USTR__STREQ(ptr, "no")) return (USTR_FALSE);
68 :
69 1 : return (!!def);
70 : }
71 :
72 : USTR_CONF_i_PROTO void ustr__cntl_mc_setup_main(void)
73 4 : {
74 4 : int val = 0;
75 :
76 4 : if (!ustr__cntl_mc_setup_env2bool("USTR_CNTL_MC", USTR_CONF_USE_ASSERT))
77 : {
78 2 : ustr__opts->umem.sys_malloc = malloc;
79 2 : ustr__opts->umem.sys_realloc = realloc;
80 2 : ustr__opts->umem.sys_free = free;
81 :
82 2 : return;
83 : }
84 :
85 2 : val = ustr__opts->mc_m_scrub;
86 2 : val = ustr__cntl_mc_setup_env2bool("USTR_CNTL_MC_M_SCRUB", val);
87 2 : ustr__opts->mc_m_scrub = val;
88 :
89 2 : val = ustr__opts->mc_f_scrub;
90 2 : val = ustr__cntl_mc_setup_env2bool("USTR_CNTL_MC_F_SCRUB", val);
91 2 : ustr__opts->mc_f_scrub = val;
92 :
93 2 : val = ustr__opts->mc_r_scrub;
94 2 : val = ustr__cntl_mc_setup_env2bool("USTR_CNTL_MC_R_SCRUB", val);
95 2 : ustr__opts->mc_r_scrub = val;
96 :
97 2 : USTR_CNTL_MALLOC_CHECK_BEG(USTR_TRUE);
98 : }
99 :
100 : USTR_CONF_i_PROTO void *ustr__cntl_mc_setup_malloc(size_t x)
101 4 : { /* again, it's not possible to call anything but malloc() or free(NULL).
102 : * So just doing setup here is fine. */
103 4 : ustr__cntl_mc_setup_main();
104 4 : return (ustr__opts->umem.sys_malloc(x));
105 : }
106 :
107 : USTR_CONF_i_PROTO void *ustr__cntl_mc_malloc(size_t x)
108 1602 : {
109 1602 : struct Ustr__cntl_mc_ptrs *ptr = ustr__cntl_mc_ptr;
110 1602 : size_t num = ustr__cntl_mc_num;
111 :
112 1602 : return (malloc_check_malloc(x, ptr[num].file, ptr[num].line, ptr[num].func));
113 : }
114 : USTR_CONF_i_PROTO void *ustr__cntl_mc_realloc(void *p, size_t x)
115 521 : {
116 521 : struct Ustr__cntl_mc_ptrs *ptr = ustr__cntl_mc_ptr;
117 521 : size_t num = ustr__cntl_mc_num;
118 :
119 521 : return (malloc_check_realloc(p,x, ptr[num].file,ptr[num].line,ptr[num].func));
120 : }
121 : USTR_CONF_i_PROTO void ustr__cntl_mc_free(void *x)
122 1488 : {
123 1488 : struct Ustr__cntl_mc_ptrs *ptr = ustr__cntl_mc_ptr;
124 1488 : size_t num = ustr__cntl_mc_num;
125 :
126 1488 : malloc_check_free(x, ptr[num].file, ptr[num].line, ptr[num].func);
127 1488 : }
128 :
129 : USTR_CONF_I_PROTO int ustr_cntl_opt(int option, ...)
130 416760 : {
131 416760 : int ret = USTR_FALSE;
132 : va_list ap;
133 :
134 416760 : va_start(ap, option);
135 :
136 416760 : switch (option)
137 : {
138 : case USTR_CNTL_OPT_GET_REF_BYTES:
139 : {
140 42 : size_t *val = va_arg(ap, size_t *);
141 :
142 42 : *val = ustr__opts->ref_bytes;
143 :
144 42 : ret = USTR_TRUE;
145 : }
146 42 : break;
147 :
148 : case USTR_CNTL_OPT_SET_REF_BYTES:
149 : {
150 10 : size_t rbytes = va_arg(ap, size_t);
151 :
152 10 : USTR_ASSERT_RET((rbytes == 0) ||
153 : (rbytes == 1) || (rbytes == 2) || (rbytes == 4) ||
154 : (USTR_CONF_HAVE_64bit_SIZE_MAX && (rbytes == 8)),
155 : USTR_FALSE);
156 :
157 10 : ustr__opts->ref_bytes = rbytes;
158 :
159 10 : ret = USTR_TRUE;
160 : }
161 10 : break;
162 :
163 : case USTR_CNTL_OPT_GET_HAS_SIZE:
164 : {
165 44 : int *val = va_arg(ap, int *);
166 :
167 44 : *val = ustr__opts->has_size;
168 :
169 44 : ret = USTR_TRUE;
170 : }
171 44 : break;
172 :
173 : case USTR_CNTL_OPT_SET_HAS_SIZE:
174 : {
175 6 : int val = va_arg(ap, int);
176 :
177 6 : USTR_ASSERT_RET((val == !!val), USTR_FALSE);
178 :
179 6 : ustr__opts->has_size = val;
180 :
181 6 : ret = USTR_TRUE;
182 : }
183 6 : break;
184 :
185 : case USTR_CNTL_OPT_GET_EXACT_BYTES:
186 : {
187 44 : int *val = va_arg(ap, int *);
188 :
189 44 : *val = ustr__opts->exact_bytes;
190 :
191 44 : ret = USTR_TRUE;
192 : }
193 44 : break;
194 :
195 : case USTR_CNTL_OPT_SET_EXACT_BYTES:
196 : {
197 2 : int val = va_arg(ap, int);
198 :
199 2 : USTR_ASSERT_RET((val == !!val), USTR_FALSE);
200 :
201 2 : ustr__opts->exact_bytes = val;
202 :
203 2 : ret = USTR_TRUE;
204 : }
205 2 : break;
206 :
207 : /* call backs */
208 :
209 : case USTR_CNTL_OPT_GET_MEM:
210 : {
211 8 : struct Ustr_cntl_mem *val = va_arg(ap, struct Ustr_cntl_mem *);
212 :
213 8 : val->sys_malloc = ustr__opts->umem.sys_malloc;
214 8 : val->sys_realloc = ustr__opts->umem.sys_realloc;
215 8 : val->sys_free = ustr__opts->umem.sys_free;
216 :
217 8 : ret = USTR_TRUE;
218 : }
219 8 : break;
220 :
221 : case USTR_CNTL_OPT_SET_MEM:
222 : {
223 44 : const struct Ustr_cntl_mem *val = va_arg(ap, struct Ustr_cntl_mem *);
224 :
225 44 : ustr__opts->umem.sys_malloc = val->sys_malloc;
226 44 : ustr__opts->umem.sys_realloc = val->sys_realloc;
227 44 : ustr__opts->umem.sys_free = val->sys_free;
228 :
229 44 : ret = USTR_TRUE;
230 : }
231 44 : break;
232 :
233 : case USTR_CNTL_OPT_GET_MC_M_SCRUB:
234 : {
235 8 : int *val = va_arg(ap, int *);
236 :
237 8 : *val = ustr__opts->mc_m_scrub;
238 :
239 8 : ret = USTR_TRUE;
240 : }
241 8 : break;
242 :
243 : case USTR_CNTL_OPT_SET_MC_M_SCRUB:
244 : {
245 2 : int val = va_arg(ap, int);
246 :
247 2 : USTR_ASSERT_RET((val == !!val), USTR_FALSE);
248 :
249 2 : ustr__opts->mc_m_scrub = val;
250 :
251 2 : ret = USTR_TRUE;
252 : }
253 2 : break;
254 :
255 : case USTR_CNTL_OPT_GET_MC_F_SCRUB:
256 : {
257 8 : int *val = va_arg(ap, int *);
258 :
259 8 : *val = ustr__opts->mc_f_scrub;
260 :
261 8 : ret = USTR_TRUE;
262 : }
263 8 : break;
264 :
265 : case USTR_CNTL_OPT_SET_MC_F_SCRUB:
266 : {
267 2 : int val = va_arg(ap, int);
268 :
269 2 : USTR_ASSERT_RET((val == !!val), USTR_FALSE);
270 :
271 2 : ustr__opts->mc_f_scrub = val;
272 :
273 2 : ret = USTR_TRUE;
274 : }
275 2 : break;
276 :
277 : case USTR_CNTL_OPT_GET_MC_R_SCRUB:
278 : {
279 8 : int *val = va_arg(ap, int *);
280 :
281 8 : *val = ustr__opts->mc_r_scrub;
282 :
283 8 : ret = USTR_TRUE;
284 : }
285 8 : break;
286 :
287 : case USTR_CNTL_OPT_SET_MC_R_SCRUB:
288 : {
289 2 : int val = va_arg(ap, int);
290 :
291 2 : USTR_ASSERT_RET((val == !!val), USTR_FALSE);
292 :
293 2 : ustr__opts->mc_r_scrub = val;
294 :
295 2 : ret = USTR_TRUE;
296 : }
297 2 : break;
298 :
299 : case 666:
300 : {
301 416523 : unsigned long valT = va_arg(ap, unsigned long);
302 416523 : int enabled = !!ustr__cntl_mc_sz;
303 :
304 416218 : USTR_ASSERT(ustr__cntl_mc_num <= ustr__cntl_mc_sz);
305 :
306 416523 : if (valT == 0x0FFE)
307 : {
308 46 : ret = ustr__cntl_mc_num + enabled;
309 46 : break;
310 : }
311 :
312 416477 : switch (valT)
313 : {
314 : case 0xF0F0:
315 : case 0xF0F1:
316 : case 0x0FF0:
317 : case 0x0FF1:
318 : case 0x0FF2:
319 : case 0x0FF3:
320 : case 0x0FF4:
321 : case 0x0FFF:
322 416477 : ret = USTR_TRUE;
323 : }
324 416195 : USTR_ASSERT(ret);
325 :
326 416477 : if (!enabled && (valT == 0x0FFF))
327 : {
328 4 : ret = USTR_FALSE;
329 4 : break;
330 : }
331 416473 : if (!enabled && (valT != 0x0FF0))
332 43 : break; /* pretend it worked */
333 :
334 416430 : switch (valT)
335 : {
336 : case 0xF0F0:
337 : {
338 218 : unsigned long valV = va_arg(ap, unsigned long);
339 218 : MALLOC_CHECK_FAIL_IN(valV);
340 : }
341 218 : break;
342 :
343 : case 0xF0F1:
344 : {
345 76 : unsigned long *valV = va_arg(ap, unsigned long *);
346 76 : *valV = MALLOC_CHECK_STORE.mem_fail_num;
347 : }
348 76 : break;
349 :
350 : case 0x0FF0:
351 : {
352 52 : const char *file = va_arg(ap, char *);
353 52 : unsigned int line = va_arg(ap, unsigned int);
354 52 : const char *func = va_arg(ap, char *);
355 52 : struct Ustr__cntl_mc_ptrs *tptr = ustr__cntl_mc_ptr;
356 52 : size_t tsz = 3;
357 :
358 52 : if (!enabled)
359 44 : tptr = MC_MALLOC(sizeof(Ustr__cntl_mc_ptrs) * tsz);
360 8 : else if (++ustr__cntl_mc_num >= ustr__cntl_mc_sz)
361 : {
362 4 : tsz = (ustr__cntl_mc_sz * 2) + 1;
363 4 : tptr = MC_REALLOC(tptr, sizeof(Ustr__cntl_mc_ptrs) * tsz);
364 : }
365 :
366 52 : if (!tptr)
367 : {
368 2 : if (enabled)
369 2 : --ustr__cntl_mc_num;
370 2 : ret = USTR_FALSE;
371 2 : break;
372 : }
373 :
374 50 : if (!enabled)
375 : {
376 44 : ustr__opts->umem.sys_malloc = ustr__cntl_mc_malloc;
377 44 : ustr__opts->umem.sys_realloc = ustr__cntl_mc_realloc;
378 44 : ustr__opts->umem.sys_free = ustr__cntl_mc_free;
379 : }
380 :
381 50 : ustr__cntl_mc_ptr = tptr;
382 50 : ustr__cntl_mc_sz = tsz;
383 :
384 50 : ustr__cntl_mc_ptr[ustr__cntl_mc_num].file = file;
385 50 : ustr__cntl_mc_ptr[ustr__cntl_mc_num].line = line;
386 50 : ustr__cntl_mc_ptr[ustr__cntl_mc_num].func = func;
387 : }
388 50 : break;
389 :
390 : case 0x0FF1:
391 : {
392 82 : struct Ustr__cntl_mc_ptrs *ptr = ustr__cntl_mc_ptr;
393 82 : size_t num = ustr__cntl_mc_num;
394 82 : void *valP = va_arg(ap, void *);
395 82 : malloc_check_mem(valP, ptr[num].file, ptr[num].line, ptr[num].func);
396 : }
397 82 : break;
398 :
399 : case 0x0FF2:
400 : {
401 415881 : struct Ustr__cntl_mc_ptrs *ptr = ustr__cntl_mc_ptr;
402 415881 : size_t num = ustr__cntl_mc_num;
403 415881 : void *valP = va_arg(ap, void *);
404 415881 : size_t valV = va_arg(ap, size_t);
405 415881 : malloc_check_mem_sz(valP, valV,
406 : ptr[num].file, ptr[num].line, ptr[num].func);
407 : }
408 415881 : break;
409 :
410 : case 0x0FF3:
411 : {
412 65 : struct Ustr__cntl_mc_ptrs *ptr = ustr__cntl_mc_ptr;
413 65 : size_t num = ustr__cntl_mc_num;
414 65 : void *valP = va_arg(ap, void *);
415 65 : size_t valV = va_arg(ap, size_t);
416 65 : malloc_check_mem_minsz(valP, valV,
417 : ptr[num].file, ptr[num].line, ptr[num].func);
418 : }
419 65 : break;
420 :
421 : case 0x0FF4:
422 : { /* needed for realloc() down doesn't fail */
423 6 : struct Ustr__cntl_mc_ptrs *ptr_mc = ustr__cntl_mc_ptr;
424 6 : size_t num_mc = ustr__cntl_mc_num;
425 6 : void *ptr = va_arg(ap, void *);
426 6 : size_t nsz = va_arg(ap, size_t);
427 : unsigned int scan = malloc_check_mem(ptr,
428 : ptr_mc[num_mc].file,
429 : ptr_mc[num_mc].line,
430 6 : ptr_mc[num_mc].func);
431 :
432 6 : MALLOC_CHECK_STORE.mem_vals[scan].sz = nsz;
433 : }
434 6 : break;
435 :
436 : case 0x0FFF:
437 : {
438 50 : const char *file = va_arg(ap, char *);
439 50 : unsigned int line = va_arg(ap, unsigned int);
440 50 : const char *func = va_arg(ap, char *);
441 :
442 50 : if (ustr__cntl_mc_num)
443 : {
444 3 : USTR_ASSERT(!strcmp(file,
445 : ustr__cntl_mc_ptr[ustr__cntl_mc_num].file));
446 3 : USTR_ASSERT(line); /* can't say much about this */
447 3 : USTR_ASSERT(!strcmp(func,
448 : ustr__cntl_mc_ptr[ustr__cntl_mc_num].func));
449 :
450 6 : --ustr__cntl_mc_num;
451 6 : break;
452 : }
453 :
454 44 : MC_FREE(ustr__cntl_mc_ptr);
455 44 : ustr__cntl_mc_num = 0;
456 44 : ustr__cntl_mc_sz = 0;
457 44 : ustr__cntl_mc_ptr = 0;
458 :
459 : /* it's bad otherwise */
460 44 : malloc_check_empty(file, line, func);
461 :
462 44 : ustr__opts->umem.sys_malloc = malloc;
463 44 : ustr__opts->umem.sys_realloc = realloc;
464 44 : ustr__opts->umem.sys_free = free;
465 :
466 44 : MALLOC_CHECK_STORE.mem_num = 0;
467 44 : MALLOC_CHECK_STORE.mem_fail_num = 0;
468 : }
469 : break;
470 : }
471 : }
472 260 : break;
473 :
474 : case USTR_CNTL_OPT_GET_FMT:
475 : {
476 4 : struct Ustr_cntl_fmt *val = va_arg(ap, struct Ustr_cntl_fmt *);
477 :
478 4 : val->sys_vsnprintf_beg = ustr__opts->ufmt.sys_vsnprintf_beg;
479 4 : val->sys_vsnprintf_end = ustr__opts->ufmt.sys_vsnprintf_end;
480 :
481 4 : ret = USTR_TRUE;
482 : }
483 4 : break;
484 :
485 : case USTR_CNTL_OPT_SET_FMT:
486 : {
487 2 : const struct Ustr_cntl_fmt *val = va_arg(ap, struct Ustr_cntl_fmt *);
488 :
489 2 : ustr__opts->ufmt.sys_vsnprintf_beg = val->sys_vsnprintf_beg;
490 2 : ustr__opts->ufmt.sys_vsnprintf_end = val->sys_vsnprintf_end;
491 :
492 2 : ret = USTR_TRUE;
493 : }
494 : /* break; */
495 :
496 1 : USTR_ASSERT_NO_SWITCH_DEF("Bad option passed to ustr_cntl_opt()");
497 : }
498 :
499 416760 : va_end(ap);
500 :
501 416760 : return (ret);
502 : }
|