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 %ld bytes\n",
00141 (long) 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 %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n",
00344 (long) 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 %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n",
00359 (long) 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 %ld bytes\n", (long) 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 %ld bytes\n", (long) 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 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (void *memory,
00533 void*
00532 dbus_realloc (