dbus-internals.c 9.13 KB
Newer Older
Havoc Pennington's avatar
Havoc Pennington committed
1 2 3
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-internals.c  random utility stuff (internal to D-BUS implementation)
 *
4
 * Copyright (C) 2002, 2003  Red Hat, Inc.
Havoc Pennington's avatar
Havoc Pennington committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Licensed under the Academic Free License version 1.2
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "dbus-internals.h"
24
#include "dbus-protocol.h"
25
#include "dbus-test.h"
Havoc Pennington's avatar
Havoc Pennington committed
26 27
#include <stdio.h>
#include <stdarg.h>
28 29 30 31 32
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
33
#include <stdlib.h>
Havoc Pennington's avatar
Havoc Pennington committed
34 35 36 37 38 39 40 41

/**
 * @defgroup DBusInternals D-BUS internal implementation details
 * @brief Documentation useful when developing or debugging D-BUS itself.
 * 
 */

/**
42
 * @defgroup DBusInternalsUtils Utilities and portability
Havoc Pennington's avatar
Havoc Pennington committed
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
 * @ingroup DBusInternals
 * @brief Utility functions (_dbus_assert(), _dbus_warn(), etc.)
 * @{
 */

/**
 * @def _dbus_assert
 *
 * Aborts with an error message if the condition is false.
 * 
 * @param condition condition which must be true.
 */

/**
 * @def _dbus_assert_not_reached
 *
 * Aborts with an error message if called.
 * The given explanation will be printed.
 * 
 * @param explanation explanation of what happened if the code was reached.
 */

/**
 * @def _DBUS_N_ELEMENTS
 *
 * Computes the number of elements in a fixed-size array using
 * sizeof().
 *
 * @param array the array to count elements in.
 */

/**
 * @def _DBUS_POINTER_TO_INT
 *
 * Safely casts a void* to an integer; should only be used on void*
 * that actually contain integers, for example one created with
 * _DBUS_INT_TO_POINTER.  Only guaranteed to preserve 32 bits.
 * (i.e. it's used to store 32-bit ints in pointers, but
 * can't be used to store 64-bit pointers in ints.)
 *
 * @param pointer pointer to extract an integer from.
 */
/**
 * @def _DBUS_INT_TO_POINTER
 *
 * Safely stuffs an integer into a pointer, to be extracted later with
 * _DBUS_POINTER_TO_INT. Only guaranteed to preserve 32 bits.
 *
 * @param integer the integer to stuff into a pointer.
 */
93 94 95 96 97 98 99
/**
 * @def _DBUS_ZERO
 *
 * Sets all bits in an object to zero.
 *
 * @param object the object to be zeroed.
 */
100 101 102 103 104 105 106 107 108 109
/**
 * @def _DBUS_INT_MIN
 *
 * Minimum value of type "int"
 */
/**
 * @def _DBUS_INT_MAX
 *
 * Maximum value of type "int"
 */
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
/**
 * @def _DBUS_MAX_SUN_PATH_LENGTH
 *
 * Maximum length of the path to a UNIX domain socket,
 * sockaddr_un::sun_path member. POSIX requires that all systems
 * support at least 100 bytes here, including the nul termination.
 * We use 99 for the max value to allow for the nul.
 *
 * We could probably also do sizeof (addr.sun_path)
 * but this way we are the same on all platforms
 * which is probably a good idea.
 */

/**
 * @typedef DBusForeachFunction
 * 
 * Used to iterate over each item in a collection, such as
 * a DBusList.
 */
129

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
/**
 * @def _DBUS_LOCK_NAME
 *
 * Expands to name of a global lock variable.
 */

/**
 * @def _DBUS_DEFINE_GLOBAL_LOCK
 *
 * Defines a global lock variable with the given name.
 * The lock must be added to the list to initialize
 * in dbus_threads_init().
 */

/**
 * @def _DBUS_DECLARE_GLOBAL_LOCK
 *
 * Expands to declaration of a global lock defined
 * with _DBUS_DEFINE_GLOBAL_LOCK.
 * The lock must be added to the list to initialize
 * in dbus_threads_init().
 */

/**
 * @def _DBUS_LOCK
 *
 * Locks a global lock
 */

/**
 * @def _DBUS_UNLOCK
 *
 * Unlocks a global lock
 */

165 166 167 168 169 170 171
/**
 * Fixed "out of memory" error message, just to avoid
 * making up a different string every time and wasting
 * space.
 */
const char _dbus_no_memory_message[] = "Not enough memory";

Havoc Pennington's avatar
Havoc Pennington committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
/**
 * Prints a warning message to stderr.
 *
 * @param format printf-style format string.
 */
void
_dbus_warn (const char *format,
            ...)
{
  /* FIXME not portable enough? */
  va_list args;

  va_start (args, format);
  vfprintf (stderr, format, args);
  va_end (args);
}

189 190 191
/**
 * Prints a warning message to stderr
 * if the user has enabled verbose mode.
192 193
 * This is the real function implementation,
 * use _dbus_verbose() macro in code.
194 195 196 197
 *
 * @param format printf-style format string.
 */
void
198 199
_dbus_verbose_real (const char *format,
                    ...)
200 201 202 203 204
{
  va_list args;
  static dbus_bool_t verbose = TRUE;
  static dbus_bool_t initted = FALSE;

205 206 207 208
  /* things are written a bit oddly here so that
   * in the non-verbose case we just have the one
   * conditional and return immediately.
   */
209 210 211 212 213
  if (!verbose)
    return;
  
  if (!initted)
    {
214
      verbose = _dbus_getenv ("DBUS_VERBOSE") != NULL;
215
      initted = TRUE;
216 217
      if (!verbose)
        return;
218 219 220 221 222 223 224
    }
  
  va_start (args, format);
  vfprintf (stderr, format, args);
  va_end (args);
}

Havoc Pennington's avatar
Havoc Pennington committed
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
/**
 * Duplicates a string. Result must be freed with
 * dbus_free(). Returns #NULL if memory allocation fails.
 * If the string to be duplicated is #NULL, returns #NULL.
 * 
 * @param str string to duplicate.
 * @returns newly-allocated copy.
 */
char*
_dbus_strdup (const char *str)
{
  int len;
  char *copy;
  
  if (str == NULL)
    return NULL;
  
  len = strlen (str);

  copy = dbus_malloc (len + 1);
  if (copy == NULL)
    return NULL;

  memcpy (copy, str, len + 1);
  
  return copy;
}

253 254 255 256 257 258 259 260 261 262 263
/**
 * Returns a string describing the given type.
 *
 * @param type the type to describe
 * @returns a constant string describing the type
 */
const char *
_dbus_type_to_string (int type)
{
  switch (type)
    {
264 265
    case DBUS_TYPE_INVALID:
      return "invalid";
266 267
    case DBUS_TYPE_NIL:
      return "nil";
268 269
    case DBUS_TYPE_BOOLEAN:
      return "boolean";
270 271 272 273 274 275 276 277
    case DBUS_TYPE_INT32:
      return "int32";
    case DBUS_TYPE_UINT32:
      return "uint32";
    case DBUS_TYPE_DOUBLE:
      return "double";
    case DBUS_TYPE_STRING:
      return "string";
278 279
    case DBUS_TYPE_BOOLEAN_ARRAY:
      return "boolean array";
280 281 282 283 284 285
    case DBUS_TYPE_INT32_ARRAY:
      return "int32 array";
    case DBUS_TYPE_UINT32_ARRAY:
      return "uint32 array";
    case DBUS_TYPE_DOUBLE_ARRAY:
      return "double array";
286 287
    case DBUS_TYPE_BYTE_ARRAY:
      return "byte array";
288 289
    case DBUS_TYPE_STRING_ARRAY:
      return "string array";
290 291 292 293 294
    default:
      return "unknown";
    }
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static dbus_bool_t
run_failing_each_malloc (int                    n_mallocs,
                         const char            *description,
                         DBusTestMemoryFunction func,
                         void                  *data)
{
  n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */
  
  while (n_mallocs >= 0)
    {      
      _dbus_set_fail_alloc_counter (n_mallocs);

      _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
                     description, n_mallocs,
                     _dbus_get_fail_alloc_failures ());

      if (!(* func) (data))
        return FALSE;
      
      n_mallocs -= 1;
    }

  _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);

  return TRUE;
}                        

/**
 * Tests how well the given function responds to out-of-memory
 * situations. Calls the function repeatedly, failing a different
 * call to malloc() each time. If the function ever returns #FALSE,
 * the test fails. The function should return #TRUE whenever something
 * valid (such as returning an error, or succeeding) occurs, and #FALSE
 * if it gets confused in some way.
 *
 * @param description description of the test used in verbose output
 * @param func function to call
 * @param data data to pass to function
 * @returns #TRUE if the function never returns FALSE
 */
dbus_bool_t
_dbus_test_oom_handling (const char             *description,
                         DBusTestMemoryFunction  func,
                         void                   *data)
{
  int approx_mallocs;

  /* Run once to see about how many mallocs are involved */
  
  _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);

  if (!(* func) (data))
    return FALSE;
348
  
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();

  _dbus_verbose ("=================\n%s: about %d mallocs total\n=================\n",
                 description, approx_mallocs);

  _dbus_set_fail_alloc_failures (1);
  if (!run_failing_each_malloc (approx_mallocs, description, func, data))
    return FALSE;

  _dbus_set_fail_alloc_failures (2);
  if (!run_failing_each_malloc (approx_mallocs, description, func, data))
    return FALSE;
  
  _dbus_set_fail_alloc_failures (3);
  if (!run_failing_each_malloc (approx_mallocs, description, func, data))
    return FALSE;

  _dbus_set_fail_alloc_failures (4);
  if (!run_failing_each_malloc (approx_mallocs, description, func, data))
    return FALSE;
  
  _dbus_verbose ("=================\n%s: all iterations passed\n=================\n",
                 description);

  return TRUE;
}

Havoc Pennington's avatar
Havoc Pennington committed
376
/** @} */