00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
#include "dbus-memory.h"
00025
#include "dbus-internals.h"
00026
#include "dbus-sysdeps.h"
00027
#include "dbus-list.h"
00028
#include <stdlib.h>
00029
00091
00098
#ifdef DBUS_BUILD_TESTS
00099
static dbus_bool_t debug_initialized =
FALSE;
00100
static int fail_nth = -1;
00101
static size_t fail_size = 0;
00102
static int fail_alloc_counter =
_DBUS_INT_MAX;
00103
static int n_failures_per_failure = 1;
00104
static int n_failures_this_failure = 0;
00105
static dbus_bool_t guards =
FALSE;
00106
static dbus_bool_t disable_mem_pools =
FALSE;
00107
static dbus_bool_t backtrace_on_fail_alloc =
FALSE;
00108
static int n_blocks_outstanding = 0;
00109
00111
#define GUARD_VALUE 0xdeadbeef
00112
00113
#define GUARD_INFO_SIZE 8
00114
00115
#define GUARD_START_PAD 16
00116
00117
#define GUARD_END_PAD 16
00118
00119
#define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
00120
00121
#define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
00122
00123
static void
00124 _dbus_initialize_malloc_debug (
void)
00125 {
00126
if (!debug_initialized)
00127 {
00128 debug_initialized =
TRUE;
00129
00130
if (
_dbus_getenv (
"DBUS_MALLOC_FAIL_NTH") !=
NULL)
00131 {
00132 fail_nth = atoi (_dbus_getenv (
"DBUS_MALLOC_FAIL_NTH"));
00133 fail_alloc_counter = fail_nth;
00134 _dbus_verbose (
"Will fail malloc every %d times\n", fail_nth);
00135 }
00136
00137
if (
_dbus_getenv (
"DBUS_MALLOC_FAIL_GREATER_THAN") !=
NULL)
00138 {
00139 fail_size = atoi (_dbus_getenv (
"DBUS_MALLOC_FAIL_GREATER_THAN"));
00140 _dbus_verbose (
"Will fail mallocs over %d bytes\n",
00141 fail_size);
00142 }
00143
00144
if (
_dbus_getenv (
"DBUS_MALLOC_GUARDS") !=
NULL)
00145 {
00146 guards =
TRUE;
00147 _dbus_verbose (
"Will use malloc guards\n");
00148 }
00149
00150
if (
_dbus_getenv (
"DBUS_DISABLE_MEM_POOLS") !=
NULL)
00151 {
00152 disable_mem_pools =
TRUE;
00153 _dbus_verbose (
"Will disable memory pools\n");
00154 }
00155
00156
if (
_dbus_getenv (
"DBUS_MALLOC_BACKTRACES") !=
NULL)
00157 {
00158 backtrace_on_fail_alloc =
TRUE;
00159 _dbus_verbose (
"Will backtrace on failing a malloc\n");
00160 }
00161 }
00162 }
00163
00169
dbus_bool_t
00170 _dbus_disable_mem_pools (
void)
00171 {
00172 _dbus_initialize_malloc_debug ();
00173
return disable_mem_pools;
00174 }
00175
00184
void
00185 _dbus_set_fail_alloc_counter (
int until_next_fail)
00186 {
00187 _dbus_initialize_malloc_debug ();
00188
00189 fail_alloc_counter = until_next_fail;
00190
00191
#if 0
00192
_dbus_verbose (
"Set fail alloc counter = %d\n", fail_alloc_counter);
00193
#endif
00194
}
00195
00202
int
00203 _dbus_get_fail_alloc_counter (
void)
00204 {
00205 _dbus_initialize_malloc_debug ();
00206
00207
return fail_alloc_counter;
00208 }
00209
00216
void
00217 _dbus_set_fail_alloc_failures (
int failures_per_failure)
00218 {
00219 n_failures_per_failure = failures_per_failure;
00220 }
00221
00228
int
00229 _dbus_get_fail_alloc_failures (
void)
00230 {
00231
return n_failures_per_failure;
00232 }
00233
00242
dbus_bool_t
00243 _dbus_decrement_fail_alloc_counter (
void)
00244 {
00245 _dbus_initialize_malloc_debug ();
00246
00247
if (fail_alloc_counter <= 0)
00248 {
00249
if (backtrace_on_fail_alloc)
00250
_dbus_print_backtrace ();
00251
00252 _dbus_verbose (
"failure %d\n", n_failures_this_failure);
00253
00254 n_failures_this_failure += 1;
00255
if (n_failures_this_failure >= n_failures_per_failure)
00256 {
00257
if (fail_nth >= 0)
00258 fail_alloc_counter = fail_nth;
00259
else
00260 fail_alloc_counter =
_DBUS_INT_MAX;
00261
00262 n_failures_this_failure = 0;
00263
00264 _dbus_verbose (
"reset fail alloc counter to %d\n", fail_alloc_counter);
00265 }
00266
00267
return TRUE;
00268 }
00269
else
00270 {
00271 fail_alloc_counter -= 1;
00272
return FALSE;
00273 }
00274 }
00275
00281
int
00282 _dbus_get_malloc_blocks_outstanding (
void)
00283 {
00284
return n_blocks_outstanding;
00285 }
00286
00290
typedef enum
00291 {
00292 SOURCE_UNKNOWN,
00293 SOURCE_MALLOC,
00294 SOURCE_REALLOC,
00295 SOURCE_MALLOC_ZERO,
00296 SOURCE_REALLOC_NULL
00297 } BlockSource;
00298
00299
static const char*
00300 source_string (BlockSource source)
00301 {
00302
switch (source)
00303 {
00304
case SOURCE_UNKNOWN:
00305
return "unknown";
00306
case SOURCE_MALLOC:
00307
return "malloc";
00308
case SOURCE_REALLOC:
00309
return "realloc";
00310
case SOURCE_MALLOC_ZERO:
00311
return "malloc0";
00312
case SOURCE_REALLOC_NULL:
00313
return "realloc(NULL)";
00314 }
00315
_dbus_assert_not_reached (
"Invalid malloc block source ID");
00316
return "invalid!";
00317 }
00318
00319
static void
00320 check_guards (
void *free_block)
00321 {
00322
if (free_block !=
NULL)
00323 {
00324
unsigned char *block = ((
unsigned char*)free_block) - GUARD_START_OFFSET;
00325 size_t requested_bytes = *(
dbus_uint32_t*)block;
00326 BlockSource source = *(
dbus_uint32_t*)(block + 4);
00327
unsigned int i;
00328
dbus_bool_t failed;
00329
00330 failed =
FALSE;
00331
00332
#if 0
00333
_dbus_verbose (
"Checking %d bytes request from source %s\n",
00334 requested_bytes, source_string (source));
00335
#endif
00336
00337 i = GUARD_INFO_SIZE;
00338
while (i < GUARD_START_OFFSET)
00339 {
00340
dbus_uint32_t value = *(
dbus_uint32_t*) &block[i];
00341
if (value != GUARD_VALUE)
00342 {
00343
_dbus_warn (
"Block of %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n",
00344 requested_bytes, source_string (source),
00345 value, i, GUARD_VALUE);
00346 failed =
TRUE;
00347 }
00348
00349 i += 4;
00350 }
00351
00352 i = GUARD_START_OFFSET + requested_bytes;
00353
while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00354 {
00355
dbus_uint32_t value = *(
dbus_uint32_t*) &block[i];
00356
if (value != GUARD_VALUE)
00357 {
00358
_dbus_warn (
"Block of %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n",
00359 requested_bytes, source_string (source),
00360 value, i, GUARD_VALUE);
00361 failed =
TRUE;
00362 }
00363
00364 i += 4;
00365 }
00366
00367
if (failed)
00368
_dbus_assert_not_reached (
"guard value corruption");
00369 }
00370 }
00371
00372
static void*
00373 set_guards (
void *real_block,
00374 size_t requested_bytes,
00375 BlockSource source)
00376 {
00377
unsigned char *block = real_block;
00378
unsigned int i;
00379
00380
if (block ==
NULL)
00381
return NULL;
00382
00383
_dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
00384
00385 *((
dbus_uint32_t*)block) = requested_bytes;
00386 *((
dbus_uint32_t*)(block + 4)) = source;
00387
00388 i = GUARD_INFO_SIZE;
00389
while (i < GUARD_START_OFFSET)
00390 {
00391 (*(
dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00392
00393 i += 4;
00394 }
00395
00396 i = GUARD_START_OFFSET + requested_bytes;
00397
while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
00398 {
00399 (*(
dbus_uint32_t*) &block[i]) = GUARD_VALUE;
00400
00401 i += 4;
00402 }
00403
00404 check_guards (block + GUARD_START_OFFSET);
00405
00406
return block + GUARD_START_OFFSET;
00407 }
00408
00409
#endif
00410
00412
00413
00429
void*
00430 dbus_malloc (size_t bytes)
00431 {
00432
#ifdef DBUS_BUILD_TESTS
00433
_dbus_initialize_malloc_debug ();
00434
00435
if (_dbus_decrement_fail_alloc_counter ())
00436 {
00437 _dbus_verbose (
" FAILING malloc of %d bytes\n", bytes);
00438
00439
return NULL;
00440 }
00441
#endif
00442
00443
if (bytes == 0)
00444
return NULL;
00445
#ifdef DBUS_BUILD_TESTS
00446
else if (fail_size != 0 && bytes > fail_size)
00447
return NULL;
00448
else if (guards)
00449 {
00450
void *block;
00451
00452 block = malloc (bytes + GUARD_EXTRA_SIZE);
00453
if (block)
00454 n_blocks_outstanding += 1;
00455
00456
return set_guards (block, bytes, SOURCE_MALLOC);
00457 }
00458
#endif
00459
else
00460 {
00461
void *mem;
00462 mem = malloc (bytes);
00463
#ifdef DBUS_BUILD_TESTS
00464
if (mem)
00465 n_blocks_outstanding += 1;
00466
#endif
00467
return mem;
00468 }
00469 }
00470
00480
void*
00481 dbus_malloc0 (size_t bytes)
00482 {
00483
#ifdef DBUS_BUILD_TESTS
00484
_dbus_initialize_malloc_debug ();
00485
00486
if (_dbus_decrement_fail_alloc_counter ())
00487 {
00488 _dbus_verbose (
" FAILING malloc0 of %d bytes\n", bytes);
00489
00490
return NULL;
00491 }
00492
#endif
00493
00494
if (bytes == 0)
00495
return NULL;
00496
#ifdef DBUS_BUILD_TESTS
00497
else if (fail_size != 0 && bytes > fail_size)
00498
return NULL;
00499
else if (guards)
00500 {
00501
void *block;
00502
00503 block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
00504
if (block)
00505 n_blocks_outstanding += 1;
00506
return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
00507 }
00508
#endif
00509
else
00510 {
00511
void *mem;
00512 mem = calloc (bytes, 1);
00513
#ifdef DBUS_BUILD_TESTS
00514
if (mem)
00515 n_blocks_outstanding += 1;
00516
#endif
00517
return mem;
00518 }
00519 }
00520
00531
void*
00532 dbus_realloc (
void *memory,
00533 size_t bytes)
00534 {
00535
#ifdef DBUS_BUILD_TESTS
00536
_dbus_initialize_malloc_debug ();
00537
00538
if (_dbus_decrement_fail_alloc_counter ())
00539 {
00540 _dbus_verbose (
" FAILING realloc of %d bytes\n", bytes);
00541
00542
return NULL;
00543 }
00544
#endif
00545
00546
if (bytes == 0)
00547 {
00548
dbus_free (memory);
00549
return NULL;
00550 }
00551
#ifdef DBUS_BUILD_TESTS
00552
else if (fail_size != 0 && bytes > fail_size)
00553
return NULL;
00554
else if (guards)
00555 {
00556
if (memory)
00557 {
00558 size_t old_bytes;
00559
void *block;
00560
00561 check_guards (memory);
00562
00563 block = realloc (((
unsigned char*)memory) - GUARD_START_OFFSET,
00564 bytes + GUARD_EXTRA_SIZE);
00565
00566 old_bytes = *(
dbus_uint32_t*)block;
00567
if (block && bytes >= old_bytes)
00568
00569 check_guards (((
unsigned char*)block) + GUARD_START_OFFSET);
00570
00571
return set_guards (block, bytes, SOURCE_REALLOC);
00572 }
00573
else
00574 {
00575
void *block;
00576
00577 block = malloc (bytes + GUARD_EXTRA_SIZE);
00578
00579
if (block)
00580 n_blocks_outstanding += 1;
00581
00582
return set_guards (block, bytes, SOURCE_REALLOC_NULL);
00583 }
00584 }
00585
#endif
00586
else
00587 {
00588
void *mem;
00589 mem = realloc (memory, bytes);
00590
#ifdef DBUS_BUILD_TESTS
00591
if (memory ==
NULL && mem !=
NULL)
00592 n_blocks_outstanding += 1;
00593
#endif
00594
return mem;
00595 }
00596 }
00597
00604
void
00605 dbus_free (
void *memory)
00606 {
00607
#ifdef DBUS_BUILD_TESTS
00608
if (guards)
00609 {
00610 check_guards (memory);
00611
if (memory)
00612 {
00613 n_blocks_outstanding -= 1;
00614
00615
_dbus_assert (n_blocks_outstanding >= 0);
00616
00617 free (((
unsigned char*)memory) - GUARD_START_OFFSET);
00618 }
00619
00620
return;
00621 }
00622
#endif
00623
00624
if (memory)
00625 {
00626
#ifdef DBUS_BUILD_TESTS
00627
n_blocks_outstanding -= 1;
00628
00629
_dbus_assert (n_blocks_outstanding >= 0);
00630
#endif
00631
00632 free (memory);
00633 }
00634 }
00635
00642
void
00643 dbus_free_string_array (
char **str_array)
00644 {
00645
if (str_array)
00646 {
00647
int i;
00648
00649 i = 0;
00650
while (str_array[i])
00651 {
00652
dbus_free (str_array[i]);
00653 i++;
00654 }
00655
00656
dbus_free (str_array);
00657 }
00658 }
00659
00661
00662
00675 int _dbus_current_generation = 1;
00676
00680 typedef struct ShutdownClosure ShutdownClosure;
00681
00685 struct ShutdownClosure
00686 {
00687 ShutdownClosure *
next;
00688 DBusShutdownFunction
func;
00689 void *
data;
00690 };
00691
00692
_DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
00693
static ShutdownClosure *registered_globals =
NULL;
00694
00703
dbus_bool_t
00704 _dbus_register_shutdown_func (DBusShutdownFunction func,
00705
void *data)
00706 {
00707
ShutdownClosure *c;
00708
00709 c =
dbus_new (
ShutdownClosure, 1);
00710
00711
if (c ==
NULL)
00712
return FALSE;
00713
00714 c->
func = func;
00715 c->
data = data;
00716
00717
_DBUS_LOCK (shutdown_funcs);
00718
00719 c->
next = registered_globals;
00720 registered_globals = c;
00721
00722
_DBUS_UNLOCK (shutdown_funcs);
00723
00724
return TRUE;
00725 }
00726
00728
00729
00748
void
00749 dbus_shutdown (
void)
00750 {
00751
while (registered_globals !=
NULL)
00752 {
00753
ShutdownClosure *c;
00754
00755 c = registered_globals;
00756 registered_globals = c->
next;
00757
00758 (* c->
func) (c->
data);
00759
00760
dbus_free (c);
00761 }
00762
00763
_dbus_current_generation += 1;
00764 }
00765
00768
#ifdef DBUS_BUILD_TESTS
00769
#include "dbus-test.h"
00770
00776
dbus_bool_t
00777 _dbus_memory_test (
void)
00778 {
00779
dbus_bool_t old_guards;
00780
void *p;
00781 size_t size;
00782
00783 old_guards = guards;
00784 guards =
TRUE;
00785 p =
dbus_malloc (4);
00786
if (p ==
NULL)
00787
_dbus_assert_not_reached (
"no memory");
00788
for (size = 4; size < 256; size += 4)
00789 {
00790 p =
dbus_realloc (p, size);
00791
if (p ==
NULL)
00792
_dbus_assert_not_reached (
"no memory");
00793 }
00794
for (size = 256; size != 0; size -= 4)
00795 {
00796 p =
dbus_realloc (p, size);
00797
if (p ==
NULL)
00798
_dbus_assert_not_reached (
"no memory");
00799 }
00800
dbus_free (p);
00801 guards = old_guards;
00802
return TRUE;
00803 }
00804
00805
#endif