(linenum→info "unix/slp.c:2238")

dbus/1.0.2/dbus/dbus-memory.c

    1: /* -*- mode: C; c-file-style: "gnu" -*- */
    2: /* dbus-memory.c  D-Bus memory handling
    3:  *
    4:  * Copyright (C) 2002, 2003  Red Hat Inc.
    5:  *
    6:  * Licensed under the Academic Free License version 2.1
    7:  * 
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 2 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  * 
   18:  * You should have received a copy of the GNU General Public License
   19:  * along with this program; if not, write to the Free Software
   20:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   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:  * @defgroup DBusMemory Memory Allocation
   32:  * @ingroup  DBus
   33:  * @brief dbus_malloc(), dbus_free(), etc.
   34:  *
   35:  * Functions and macros related to allocating and releasing
   36:  * blocks of memory.
   37:  *
   38:  */
   39: 
   40: /**
   41:  * @defgroup DBusMemoryInternals Memory allocation implementation details
   42:  * @ingroup  DBusInternals
   43:  * @brief internals of dbus_malloc() etc.
   44:  *
   45:  * Implementation details related to allocating and releasing blocks
   46:  * of memory.
   47:  */
   48: 
   49: /**
   50:  * @addtogroup DBusMemory
   51:  *
   52:  * @{
   53:  */
   54: 
   55: /**
   56:  * @def dbus_new
   57:  *
   58:  * Safe macro for using dbus_malloc(). Accepts the type
   59:  * to allocate and the number of type instances to
   60:  * allocate as arguments, and returns a memory block
   61:  * cast to the desired type, instead of as a void*.
   62:  *
   63:  * @param type type name to allocate
   64:  * @param count number of instances in the allocated array
   65:  * @returns the new memory block or #NULL on failure
   66:  */
   67: 
   68: /**
   69:  * @def dbus_new0
   70:  *
   71:  * Safe macro for using dbus_malloc0(). Accepts the type
   72:  * to allocate and the number of type instances to
   73:  * allocate as arguments, and returns a memory block
   74:  * cast to the desired type, instead of as a void*.
   75:  * The allocated array is initialized to all-bits-zero.
   76:  *
   77:  * @param type type name to allocate
   78:  * @param count number of instances in the allocated array
   79:  * @returns the new memory block or #NULL on failure
   80:  */
   81: 
   82: /**
   83:  * @typedef DBusFreeFunction
   84:  *
   85:  * The type of a function which frees a block of memory.
   86:  *
   87:  * @param memory the memory to free
   88:  */
   89: 
   90: /** @} */ /* end of public API docs */
   91: 
   92: /**
   93:  * @addtogroup DBusMemoryInternals
   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: /** value stored in guard padding for debugging buffer overrun */
  111: #define GUARD_VALUE 0xdeadbeef
  112: /** size of the information about the block stored in guard mode */
  113: #define GUARD_INFO_SIZE 8
  114: /** size of the GUARD_VALUE-filled padding after the header info  */
  115: #define GUARD_START_PAD 16
  116: /** size of the GUARD_VALUE-filled padding at the end of the block */
  117: #define GUARD_END_PAD 16
  118: /** size of stuff at start of block */
  119: #define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
  120: /** total extra size over the requested allocation for guard stuff */
  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:  * Whether to turn off mem pools, useful for leak checking.
  166:  *
  167:  * @returns #TRUE if mempools should not be used.
  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:  * Sets the number of allocations until we simulate a failed
  178:  * allocation. If set to 0, the next allocation to run
  179:  * fails; if set to 1, one succeeds then the next fails; etc.
  180:  * Set to _DBUS_INT_MAX to not fail anything. 
  181:  *
  182:  * @param until_next_fail number of successful allocs before one fails
  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:  * Gets the number of successful allocs until we'll simulate
  198:  * a failed alloc.
  199:  *
  200:  * @returns current counter value
  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:  * Sets how many mallocs to fail when the fail alloc counter reaches
  212:  * 0.
  213:  *
  214:  * @param failures_per_failure number to fail
  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:  * Gets the number of failures we'll have when the fail malloc
  224:  * counter reaches 0.
  225:  *
  226:  * @returns number of failures planned
  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:  * Called when about to alloc some memory; if
  237:  * it returns #TRUE, then the allocation should
  238:  * fail. If it returns #FALSE, then the allocation
  239:  * should not fail.
  240:  *
  241:  * @returns #TRUE if this alloc should fail
  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 /* DBUS_BUILD_TESTS */
  277: 
  278: /**
  279:  * Get the number of outstanding malloc()'d blocks.
  280:  *
  281:  * @returns number of blocks
  282:  */
  283: int
  284: _dbus_get_malloc_blocks_outstanding (void)
  285: {
  286:   return n_blocks_outstanding.value;
  287: }
  288: 
  289: /**
  290:  * Where the block came from.
  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:       /* set memory to anything but nul bytes */
  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: /** @} */ /* End of internals docs */
  419: 
  420: 
  421: /**
  422:  * @addtogroup DBusMemory
  423:  *
  424:  * @{
  425:  */
  426: 
  427: /**
  428:  * Allocates the given number of bytes, as with standard
  429:  * malloc(). Guaranteed to return #NULL if bytes is zero
  430:  * on all platforms. Returns #NULL if the allocation fails.
  431:  * The memory must be released with dbus_free().
  432:  *
  433:  * dbus_malloc() memory is NOT safe to free with regular free() from
  434:  * the C library. Free it with dbus_free() only.
  435:  *
  436:  * @param bytes number of bytes to allocate
  437:  * @return allocated memory, or #NULL if the allocation fails.
  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) /* some system mallocs handle this, some don't */
  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:  * Allocates the given number of bytes, as with standard malloc(), but
  482:  * all bytes are initialized to zero as with calloc(). Guaranteed to
  483:  * return #NULL if bytes is zero on all platforms. Returns #NULL if the
  484:  * allocation fails.  The memory must be released with dbus_free().
  485:  *
  486:  * dbus_malloc0() memory is NOT safe to free with regular free() from
  487:  * the C library. Free it with dbus_free() only.
  488:  *
  489:  * @param bytes number of bytes to allocate
  490:  * @return allocated memory, or #NULL if the allocation fails.
  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:  * Resizes a block of memory previously allocated by dbus_malloc() or
  535:  * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes
  536:  * is zero on all platforms. Returns #NULL if the resize fails.
  537:  * If the resize fails, the memory is not freed.
  538:  *
  539:  * @param memory block to be resized
  540:  * @param bytes new size of the memory block
  541:  * @return allocated memory, or #NULL if the resize fails.
  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) /* guarantee this is safe */
  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:             /* old guards shouldn't have moved */
  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:  * Frees a block of memory previously allocated by dbus_malloc() or
  612:  * dbus_malloc0(). If passed #NULL, does nothing.
  613:  * 
  614:  * @param memory block to be freed
  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) /* we guarantee it's safe to free (NULL) */
  637:     {
  638: #ifdef DBUS_BUILD_TESTS
  639:       _dbus_atomic_dec (&n_blocks_outstanding);
  640:       
  641: