1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #include "dbus-memory.h"
25: #include "dbus-internals.h"
26: #include "dbus-sysdeps.h"
27: #include "dbus-list.h"
28: #include <stdlib.h>
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98: #ifdef DBUS_BUILD_TESTS
99: static dbus_bool_t debug_initialized = FALSE;
100: static int fail_nth = -1;
101: static size_t fail_size = 0;
102: static int fail_alloc_counter = _DBUS_INT_MAX;
103: static int n_failures_per_failure = 1;
104: static int n_failures_this_failure = 0;
105: static dbus_bool_t guards = FALSE;
106: static dbus_bool_t disable_mem_pools = FALSE;
107: static dbus_bool_t backtrace_on_fail_alloc = FALSE;
108: static DBusAtomic n_blocks_outstanding = {0};
109:
110:
111: #define GUARD_VALUE 0xdeadbeef
112:
113: #define GUARD_INFO_SIZE 8
114:
115: #define GUARD_START_PAD 16
116:
117: #define GUARD_END_PAD 16
118:
119: #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
120:
121: #define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
122:
123: static void
124: _dbus_initialize_malloc_debug (void)
125: {
126: if (!debug_initialized)
127: {
128: debug_initialized = TRUE;
129:
130: if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL)
131: {
132: fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
133: fail_alloc_counter = fail_nth;
134: _dbus_verbose ("Will fail malloc every %d times\n", fail_nth);
135: }
136:
137: if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
138: {
139: fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
140: _dbus_verbose ("Will fail mallocs over %ld bytes\n",
141: (long) fail_size);
142: }
143:
144: if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
145: {
146: guards = TRUE;
147: _dbus_verbose ("Will use malloc guards\n");
148: }
149:
150: if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
151: {
152: disable_mem_pools = TRUE;
153: _dbus_verbose ("Will disable memory pools\n");
154: }
155:
156: if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
157: {
158: backtrace_on_fail_alloc = TRUE;
159: _dbus_verbose ("Will backtrace on failing a malloc\n");
160: }
161: }
162: }
163:
164:
165:
166:
167:
168:
169: dbus_bool_t
170: _dbus_disable_mem_pools (void)
171: {
172: _dbus_initialize_malloc_debug ();
173: return disable_mem_pools;
174: }
175:
176:
177:
178:
179:
180:
181:
182:
183:
184: void
185: _dbus_set_fail_alloc_counter (int until_next_fail)
186: {
187: _dbus_initialize_malloc_debug ();
188:
189: fail_alloc_counter = until_next_fail;
190:
191: #if 0
192: _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter);
193: #endif
194: }
195:
196:
197:
198:
199:
200:
201:
202: int
203: _dbus_get_fail_alloc_counter (void)
204: {
205: _dbus_initialize_malloc_debug ();
206:
207: return fail_alloc_counter;
208: }
209:
210:
211:
212:
213:
214:
215:
216: void
217: _dbus_set_fail_alloc_failures (int failures_per_failure)
218: {
219: n_failures_per_failure = failures_per_failure;
220: }
221:
222:
223:
224:
225:
226:
227:
228: int
229: _dbus_get_fail_alloc_failures (void)
230: {
231: return n_failures_per_failure;
232: }
233:
234: #ifdef DBUS_BUILD_TESTS
235:
236:
237:
238:
239:
240:
241:
242:
243: dbus_bool_t
244: _dbus_decrement_fail_alloc_counter (void)
245: {
246: _dbus_initialize_malloc_debug ();
247:
248: if (fail_alloc_counter <= 0)
249: {
250: if (backtrace_on_fail_alloc)
251: _dbus_print_backtrace ();
252:
253: _dbus_verbose ("failure %d\n", n_failures_this_failure);
254:
255: n_failures_this_failure += 1;
256: if (n_failures_this_failure >= n_failures_per_failure)
257: {
258: if (fail_nth >= 0)
259: fail_alloc_counter = fail_nth;
260: else
261: fail_alloc_counter = _DBUS_INT_MAX;
262:
263: n_failures_this_failure = 0;
264:
265: _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter);
266: }
267:
268: return TRUE;
269: }
270: else
271: {
272: fail_alloc_counter -= 1;
273: return FALSE;
274: }
275: }
276: #endif
277:
278:
279:
280:
281:
282:
283: int
284: _dbus_get_malloc_blocks_outstanding (void)
285: {
286: return n_blocks_outstanding.value;
287: }
288:
289:
290:
291:
292: typedef enum
293: {
294: SOURCE_UNKNOWN,
295: SOURCE_MALLOC,
296: SOURCE_REALLOC,
297: SOURCE_MALLOC_ZERO,
298: SOURCE_REALLOC_NULL
299: } BlockSource;
300:
301: static const char*
302: source_string (BlockSource source)
303: {
304: switch (source)
305: {
306: case SOURCE_UNKNOWN:
307: return "unknown";
308: case SOURCE_MALLOC:
309: return "malloc";
310: case SOURCE_REALLOC:
311: return "realloc";
312: case SOURCE_MALLOC_ZERO:
313: return "malloc0";
314: case SOURCE_REALLOC_NULL:
315: return "realloc(NULL)";
316: }
317: _dbus_assert_not_reached ("Invalid malloc block source ID");
318: return "invalid!";
319: }
320:
321: static void
322: check_guards (void *free_block,
323: dbus_bool_t overwrite)
324: {
325: if (free_block != NULL)
326: {
327: unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
328: size_t requested_bytes = *(dbus_uint32_t*)block;
329: BlockSource source = *(dbus_uint32_t*)(block + 4);
330: unsigned int i;
331: dbus_bool_t failed;
332:
333: failed = FALSE;
334:
335: #if 0
336: _dbus_verbose ("Checking %d bytes request from source %s\n",
337: requested_bytes, source_string (source));
338: #endif
339:
340: i = GUARD_INFO_SIZE;
341: while (i < GUARD_START_OFFSET)
342: {
343: dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
344: if (value != GUARD_VALUE)
345: {
346: _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
347: (long) requested_bytes, source_string (source),
348: value, i, GUARD_VALUE);
349: failed = TRUE;
350: }
351:
352: i += 4;
353: }
354:
355: i = GUARD_START_OFFSET + requested_bytes;
356: while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
357: {
358: dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
359: if (value != GUARD_VALUE)
360: {
361: _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n",
362: (long) requested_bytes, source_string (source),
363: value, i, GUARD_VALUE);
364: failed = TRUE;
365: }
366:
367: i += 4;
368: }
369:
370:
371: if (overwrite)
372: memset (free_block, 'g', requested_bytes);
373:
374: if (failed)
375: _dbus_assert_not_reached ("guard value corruption");
376: }
377: }
378:
379: static void*
380: set_guards (void *real_block,
381: size_t requested_bytes,
382: BlockSource source)
383: {
384: unsigned char *block = real_block;
385: unsigned int i;
386:
387: if (block == NULL)
388: return NULL;
389:
390: _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
391:
392: *((dbus_uint32_t*)block) = requested_bytes;
393: *((dbus_uint32_t*)(block + 4)) = source;
394:
395: i = GUARD_INFO_SIZE;
396: while (i < GUARD_START_OFFSET)
397: {
398: (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
399:
400: i += 4;
401: }
402:
403: i = GUARD_START_OFFSET + requested_bytes;
404: while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
405: {
406: (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
407:
408: i += 4;
409: }
410:
411: check_guards (block + GUARD_START_OFFSET, FALSE);
412:
413: return block + GUARD_START_OFFSET;
414: }
415:
416: #endif
417:
418:
419:
420:
421:
422:
423:
424:
425:
426:
427:
428:
429:
430:
431:
432:
433:
434:
435:
436:
437:
438:
439: void*
440: dbus_malloc (size_t bytes)
441: {
442: #ifdef DBUS_BUILD_TESTS
443: _dbus_initialize_malloc_debug ();
444:
445: if (_dbus_decrement_fail_alloc_counter ())
446: {
447: _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes);
448: return NULL;
449: }
450: #endif
451:
452: if (bytes == 0)
453: return NULL;
454: #ifdef DBUS_BUILD_TESTS
455: else if (fail_size != 0 && bytes > fail_size)
456: return NULL;
457: else if (guards)
458: {
459: void *block;
460:
461: block = malloc (bytes + GUARD_EXTRA_SIZE);
462: if (block)
463: _dbus_atomic_inc (&n_blocks_outstanding);
464:
465: return set_guards (block, bytes, SOURCE_MALLOC);
466: }
467: #endif
468: else
469: {
470: void *mem;
471: mem = malloc (bytes);
472: #ifdef DBUS_BUILD_TESTS
473: if (mem)
474: _dbus_atomic_inc (&n_blocks_outstanding);
475: #endif
476: return mem;
477: }
478: }
479:
480:
481:
482:
483:
484:
485:
486:
487:
488:
489:
490:
491:
492: void*
493: dbus_malloc0 (size_t bytes)
494: {
495: #ifdef DBUS_BUILD_TESTS
496: _dbus_initialize_malloc_debug ();
497:
498: if (_dbus_decrement_fail_alloc_counter ())
499: {
500: _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes);
501:
502: return NULL;
503: }
504: #endif
505:
506: if (bytes == 0)
507: return NULL;
508: #ifdef DBUS_BUILD_TESTS
509: else if (fail_size != 0 && bytes > fail_size)
510: return NULL;
511: else if (guards)
512: {
513: void *block;
514:
515: block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
516: if (block)
517: _dbus_atomic_inc (&n_blocks_outstanding);
518: return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
519: }
520: #endif
521: else
522: {
523: void *mem;
524: mem = calloc (bytes, 1);
525: #ifdef DBUS_BUILD_TESTS
526: if (mem)
527: _dbus_atomic_inc (&n_blocks_outstanding);
528: #endif
529: return mem;
530: }
531: }
532:
533:
534:
535:
536:
537:
538:
539:
540:
541:
542:
543: void*
544: dbus_realloc (void *memory,
545: size_t bytes)
546: {
547: #ifdef DBUS_BUILD_TESTS
548: _dbus_initialize_malloc_debug ();
549:
550: if (_dbus_decrement_fail_alloc_counter ())
551: {
552: _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes);
553:
554: return NULL;
555: }
556: #endif
557:
558: if (bytes == 0)
559: {
560: dbus_free (memory);
561: return NULL;
562: }
563: #ifdef DBUS_BUILD_TESTS
564: else if (fail_size != 0 && bytes > fail_size)
565: return NULL;
566: else if (guards)
567: {
568: if (memory)
569: {
570: size_t old_bytes;
571: void *block;
572:
573: check_guards (memory, FALSE);
574:
575: block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
576: bytes + GUARD_EXTRA_SIZE);
577:
578: old_bytes = *(dbus_uint32_t*)block;
579: if (block && bytes >= old_bytes)
580:
581: check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
582:
583: return set_guards (block, bytes, SOURCE_REALLOC);
584: }
585: else
586: {
587: void *block;
588:
589: block = malloc (bytes + GUARD_EXTRA_SIZE);
590:
591: if (block)
592: _dbus_atomic_inc (&n_blocks_outstanding);
593:
594: return set_guards (block, bytes, SOURCE_REALLOC_NULL);
595: }
596: }
597: #endif
598: else
599: {
600: void *mem;
601: mem = realloc (memory, bytes);
602: #ifdef DBUS_BUILD_TESTS
603: if (memory == NULL && mem != NULL)
604: _dbus_atomic_inc (&n_blocks_outstanding);
605: #endif
606: return mem;
607: }
608: }
609:
610:
611:
612:
613:
614:
615:
616: void
617: dbus_free (void *memory)
618: {
619: #ifdef DBUS_BUILD_TESTS
620: if (guards)
621: {
622: check_guards (memory, TRUE);
623: if (memory)
624: {
625: _dbus_atomic_dec (&n_blocks_outstanding);
626:
627: _dbus_assert (n_blocks_outstanding.value >= 0);
628:
629: free (((unsigned char*)memory) - GUARD_START_OFFSET);
630: }
631:
632: return;
633: }
634: #endif
635:
636: if (memory)
637: {
638: #ifdef DBUS_BUILD_TESTS
639: _dbus_atomic_dec (&n_blocks_outstanding);
640:
641: