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 <config.h>
00025 #include "dbus-internals.h"
00026 #include "dbus-protocol.h"
00027 #include "dbus-marshal-basic.h"
00028 #include "dbus-test.h"
00029 #include "dbus-valgrind-internal.h"
00030 #include <stdio.h>
00031 #include <stdarg.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00035 #include <windows.h>
00036 #include <mbstring.h>
00037 #endif
00038
00184 const char *_dbus_no_memory_message = "Not enough memory";
00185
00186 static dbus_bool_t warn_initted = FALSE;
00187 static dbus_bool_t fatal_warnings = FALSE;
00188 static dbus_bool_t fatal_warnings_on_check_failed = TRUE;
00189
00190 static void
00191 init_warnings(void)
00192 {
00193 if (!warn_initted)
00194 {
00195 const char *s;
00196 s = _dbus_getenv ("DBUS_FATAL_WARNINGS");
00197 if (s && *s)
00198 {
00199 if (*s == '0')
00200 {
00201 fatal_warnings = FALSE;
00202 fatal_warnings_on_check_failed = FALSE;
00203 }
00204 else if (*s == '1')
00205 {
00206 fatal_warnings = TRUE;
00207 fatal_warnings_on_check_failed = TRUE;
00208 }
00209 else
00210 {
00211 fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'",
00212 s);
00213 }
00214 }
00215
00216 warn_initted = TRUE;
00217 }
00218 }
00219
00229 void
00230 _dbus_warn (const char *format,
00231 ...)
00232 {
00233 va_list args;
00234
00235 if (!warn_initted)
00236 init_warnings ();
00237
00238 va_start (args, format);
00239 vfprintf (stderr, format, args);
00240 va_end (args);
00241
00242 if (fatal_warnings)
00243 {
00244 fflush (stderr);
00245 _dbus_abort ();
00246 }
00247 }
00248
00257 void
00258 _dbus_warn_check_failed(const char *format,
00259 ...)
00260 {
00261 va_list args;
00262
00263 if (!warn_initted)
00264 init_warnings ();
00265
00266 fprintf (stderr, "process %lu: ", _dbus_pid_for_log ());
00267
00268 va_start (args, format);
00269 vfprintf (stderr, format, args);
00270 va_end (args);
00271
00272 if (fatal_warnings_on_check_failed)
00273 {
00274 fflush (stderr);
00275 _dbus_abort ();
00276 }
00277 }
00278
00279 #ifdef DBUS_ENABLE_VERBOSE_MODE
00280
00281 static dbus_bool_t verbose_initted = FALSE;
00282 static dbus_bool_t verbose = TRUE;
00283
00285 #define PTHREAD_IN_VERBOSE 0
00286 #if PTHREAD_IN_VERBOSE
00287 #include <pthread.h>
00288 #endif
00289
00290 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00291 static char module_name[1024];
00292 #endif
00293
00294 static inline void
00295 _dbus_verbose_init (void)
00296 {
00297 if (!verbose_initted)
00298 {
00299 const char *p = _dbus_getenv ("DBUS_VERBOSE");
00300 verbose = p != NULL && *p == '1';
00301 verbose_initted = TRUE;
00302 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00303 {
00304 char *last_period, *last_slash;
00305 GetModuleFileName(0,module_name,sizeof(module_name)-1);
00306 last_period = _mbsrchr(module_name,'.');
00307 if (last_period)
00308 *last_period ='\0';
00309 last_slash = _mbsrchr(module_name,'\\');
00310 if (last_slash)
00311 strcpy(module_name,last_slash+1);
00312 strcat(module_name,": ");
00313 }
00314 #endif
00315 }
00316 }
00317
00323 #ifdef DBUS_WIN
00324 #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
00325 #else
00326 #define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
00327 #endif
00328
00333 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
00334 {
00335 int prefix = 0;
00336 char *p = (char *)file + strlen(file);
00337 int i = 0;
00338
00339 for (;p >= file;p--)
00340 {
00341 if (DBUS_IS_DIR_SEPARATOR(*p))
00342 {
00343 if (++i >= level)
00344 {
00345 prefix = p-file+1;
00346 break;
00347 }
00348 }
00349 }
00350
00351 return (char *)file+prefix;
00352 }
00353
00359 dbus_bool_t
00360 _dbus_is_verbose_real (void)
00361 {
00362 _dbus_verbose_init ();
00363 return verbose;
00364 }
00365
00366 void _dbus_set_verbose (dbus_bool_t state)
00367 {
00368 verbose = state;
00369 }
00370
00371 dbus_bool_t _dbus_get_verbose (void)
00372 {
00373 return verbose;
00374 }
00375
00384 void
00385 _dbus_verbose_real (
00386 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00387 const char *file,
00388 const int line,
00389 const char *function,
00390 #endif
00391 const char *format,
00392 ...)
00393 {
00394 va_list args;
00395 static dbus_bool_t need_pid = TRUE;
00396 int len;
00397
00398
00399
00400
00401
00402 if (!_dbus_is_verbose_real())
00403 return;
00404
00405 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING
00406
00407 if (need_pid)
00408 {
00409 #if PTHREAD_IN_VERBOSE
00410 fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());
00411 #else
00412 fprintf (stderr, "%lu: ", _dbus_pid_for_log ());
00413 #endif
00414 }
00415 #endif
00416
00417
00418 len = strlen (format);
00419 if (format[len-1] == '\n')
00420 need_pid = TRUE;
00421 else
00422 need_pid = FALSE;
00423
00424 va_start (args, format);
00425 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00426 {
00427 char buf[1024];
00428 strcpy(buf,module_name);
00429 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00430 sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00431 #endif
00432 vsprintf (buf+strlen(buf),format, args);
00433 va_end (args);
00434 OutputDebugStringA(buf);
00435 }
00436 #else
00437 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00438 fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00439 #endif
00440
00441 vfprintf (stderr, format, args);
00442 va_end (args);
00443
00444 fflush (stderr);
00445 #endif
00446 }
00447
00454 void
00455 _dbus_verbose_reset_real (void)
00456 {
00457 verbose_initted = FALSE;
00458 }
00459
00460 void
00461 _dbus_trace_ref (const char *obj_name,
00462 void *obj,
00463 int old_refcount,
00464 int new_refcount,
00465 const char *why,
00466 const char *env_var,
00467 int *enabled)
00468 {
00469 _dbus_assert (obj_name != NULL);
00470 _dbus_assert (obj != NULL);
00471 _dbus_assert (old_refcount >= -1);
00472 _dbus_assert (new_refcount >= -1);
00473
00474 if (old_refcount == -1)
00475 {
00476 _dbus_assert (new_refcount == -1);
00477 }
00478 else
00479 {
00480 _dbus_assert (new_refcount >= 0);
00481 _dbus_assert (old_refcount >= 0);
00482 _dbus_assert (old_refcount > 0 || new_refcount > 0);
00483 }
00484
00485 _dbus_assert (why != NULL);
00486 _dbus_assert (env_var != NULL);
00487 _dbus_assert (enabled != NULL);
00488
00489 if (*enabled < 0)
00490 {
00491 const char *s = _dbus_getenv (env_var);
00492
00493 *enabled = FALSE;
00494
00495 if (s && *s)
00496 {
00497 if (*s == '0')
00498 *enabled = FALSE;
00499 else if (*s == '1')
00500 *enabled = TRUE;
00501 else
00502 _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s);
00503 }
00504 }
00505
00506 if (*enabled)
00507 {
00508 if (old_refcount == -1)
00509 {
00510 VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)",
00511 obj_name, obj, why);
00512 _dbus_verbose ("%s %p ref stolen (%s)\n",
00513 obj_name, obj, why);
00514 }
00515 else
00516 {
00517 VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)",
00518 obj_name, obj,
00519 old_refcount, new_refcount, why);
00520 _dbus_verbose ("%s %p %d -> %d refs (%s)\n",
00521 obj_name, obj, old_refcount, new_refcount, why);
00522 }
00523 }
00524 }
00525
00526 #endif
00527
00536 char*
00537 _dbus_strdup (const char *str)
00538 {
00539 size_t len;
00540 char *copy;
00541
00542 if (str == NULL)
00543 return NULL;
00544
00545 len = strlen (str);
00546
00547 copy = dbus_malloc (len + 1);
00548 if (copy == NULL)
00549 return NULL;
00550
00551 memcpy (copy, str, len + 1);
00552
00553 return copy;
00554 }
00555
00564 void*
00565 _dbus_memdup (const void *mem,
00566 size_t n_bytes)
00567 {
00568 void *copy;
00569
00570 copy = dbus_malloc (n_bytes);
00571 if (copy == NULL)
00572 return NULL;
00573
00574 memcpy (copy, mem, n_bytes);
00575
00576 return copy;
00577 }
00578
00587 char**
00588 _dbus_dup_string_array (const char **array)
00589 {
00590 int len;
00591 int i;
00592 char **copy;
00593
00594 if (array == NULL)
00595 return NULL;
00596
00597 for (len = 0; array[len] != NULL; ++len)
00598 ;
00599
00600 copy = dbus_new0 (char*, len + 1);
00601 if (copy == NULL)
00602 return NULL;
00603
00604 i = 0;
00605 while (i < len)
00606 {
00607 copy[i] = _dbus_strdup (array[i]);
00608 if (copy[i] == NULL)
00609 {
00610 dbus_free_string_array (copy);
00611 return NULL;
00612 }
00613
00614 ++i;
00615 }
00616
00617 return copy;
00618 }
00619
00627 dbus_bool_t
00628 _dbus_string_array_contains (const char **array,
00629 const char *str)
00630 {
00631 int i;
00632
00633 i = 0;
00634 while (array[i] != NULL)
00635 {
00636 if (strcmp (array[i], str) == 0)
00637 return TRUE;
00638 ++i;
00639 }
00640
00641 return FALSE;
00642 }
00643
00652 dbus_bool_t
00653 _dbus_generate_uuid (DBusGUID *uuid,
00654 DBusError *error)
00655 {
00656 DBusError rand_error;
00657 long now;
00658
00659 dbus_error_init (&rand_error);
00660
00661
00662
00663
00664 _dbus_get_real_time (&now, NULL);
00665
00666 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00667
00668 if (!_dbus_generate_random_bytes_buffer (uuid->as_bytes,
00669 DBUS_UUID_LENGTH_BYTES - 4,
00670 &rand_error))
00671 {
00672 dbus_set_error (error, rand_error.name,
00673 "Failed to generate UUID: %s", rand_error.message);
00674 dbus_error_free (&rand_error);
00675 return FALSE;
00676 }
00677
00678 return TRUE;
00679 }
00680
00688 dbus_bool_t
00689 _dbus_uuid_encode (const DBusGUID *uuid,
00690 DBusString *encoded)
00691 {
00692 DBusString binary;
00693 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00694 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00695 }
00696
00697 static dbus_bool_t
00698 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00699 DBusGUID *uuid,
00700 DBusError *error)
00701 {
00702 DBusString contents;
00703 DBusString decoded;
00704 int end;
00705
00706 if (!_dbus_string_init (&contents))
00707 {
00708 _DBUS_SET_OOM (error);
00709 return FALSE;
00710 }
00711
00712 if (!_dbus_string_init (&decoded))
00713 {
00714 _dbus_string_free (&contents);
00715 _DBUS_SET_OOM (error);
00716 return FALSE;
00717 }
00718
00719 if (!_dbus_file_get_contents (&contents, filename, error))
00720 goto error;
00721
00722 _dbus_string_chop_white (&contents);
00723
00724 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00725 {
00726 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00727 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00728 _dbus_string_get_const_data (filename),
00729 DBUS_UUID_LENGTH_HEX,
00730 _dbus_string_get_length (&contents));
00731 goto error;
00732 }
00733
00734 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00735 {
00736 _DBUS_SET_OOM (error);
00737 goto error;
00738 }
00739
00740 if (end == 0)
00741 {
00742 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00743 "UUID file '%s' contains invalid hex data",
00744 _dbus_string_get_const_data (filename));
00745 goto error;
00746 }
00747
00748 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00749 {
00750 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00751 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00752 _dbus_string_get_const_data (filename),
00753 _dbus_string_get_length (&decoded),
00754 DBUS_UUID_LENGTH_BYTES);
00755 goto error;
00756 }
00757
00758 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00759
00760 _dbus_string_free (&decoded);
00761 _dbus_string_free (&contents);
00762
00763 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00764
00765 return TRUE;
00766
00767 error:
00768 _DBUS_ASSERT_ERROR_IS_SET (error);
00769 _dbus_string_free (&contents);
00770 _dbus_string_free (&decoded);
00771 return FALSE;
00772 }
00773
00782 dbus_bool_t
00783 _dbus_write_uuid_file (const DBusString *filename,
00784 const DBusGUID *uuid,
00785 DBusError *error)
00786 {
00787 DBusString encoded;
00788
00789 if (!_dbus_string_init (&encoded))
00790 {
00791 _DBUS_SET_OOM (error);
00792 return FALSE;
00793 }
00794
00795 if (!_dbus_uuid_encode (uuid, &encoded))
00796 {
00797 _DBUS_SET_OOM (error);
00798 goto error;
00799 }
00800
00801 if (!_dbus_string_append_byte (&encoded, '\n'))
00802 {
00803 _DBUS_SET_OOM (error);
00804 goto error;
00805 }
00806
00807 if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
00808 goto error;
00809
00810 _dbus_string_free (&encoded);
00811
00812 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00813 return TRUE;
00814
00815 error:
00816 _DBUS_ASSERT_ERROR_IS_SET (error);
00817 _dbus_string_free (&encoded);
00818 return FALSE;
00819 }
00820
00831 dbus_bool_t
00832 _dbus_read_uuid_file (const DBusString *filename,
00833 DBusGUID *uuid,
00834 dbus_bool_t create_if_not_found,
00835 DBusError *error)
00836 {
00837 DBusError read_error = DBUS_ERROR_INIT;
00838
00839 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00840 return TRUE;
00841
00842 if (!create_if_not_found)
00843 {
00844 dbus_move_error (&read_error, error);
00845 return FALSE;
00846 }
00847
00848
00849
00850
00851
00852 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00853 {
00854 dbus_move_error (&read_error, error);
00855 return FALSE;
00856 }
00857 else
00858 {
00859 dbus_error_free (&read_error);
00860
00861 if (!_dbus_generate_uuid (uuid, error))
00862 return FALSE;
00863
00864 return _dbus_write_uuid_file (filename, uuid, error);
00865 }
00866 }
00867
00868
00869 static int machine_uuid_initialized_generation = 0;
00870 static DBusGUID machine_uuid;
00871
00883 dbus_bool_t
00884 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str,
00885 DBusError *error)
00886 {
00887 dbus_bool_t ok = TRUE;
00888
00889 if (!_DBUS_LOCK (machine_uuid))
00890 {
00891 _DBUS_SET_OOM (error);
00892 return FALSE;
00893 }
00894
00895 if (machine_uuid_initialized_generation != _dbus_current_generation)
00896 {
00897 DBusError local_error = DBUS_ERROR_INIT;
00898
00899 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00900 &local_error))
00901 {
00902 #ifndef DBUS_ENABLE_EMBEDDED_TESTS
00903
00904
00905
00906
00907 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00908 "See the manual page for dbus-uuidgen to correct this issue.\n",
00909 local_error.message);
00910 #endif
00911
00912 dbus_error_free (&local_error);
00913
00914 ok = _dbus_generate_uuid (&machine_uuid, error);
00915 }
00916 }
00917
00918 if (ok)
00919 {
00920 if (!_dbus_uuid_encode (&machine_uuid, uuid_str))
00921 {
00922 ok = FALSE;
00923 _DBUS_SET_OOM (error);
00924 }
00925 }
00926
00927 _DBUS_UNLOCK (machine_uuid);
00928
00929 return ok;
00930 }
00931
00932 #ifndef DBUS_DISABLE_CHECKS
00933
00934 const char *_dbus_return_if_fail_warning_format =
00935 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00936 "This is normally a bug in some application using the D-Bus library.\n";
00937 #endif
00938
00939 #ifndef DBUS_DISABLE_ASSERT
00940
00952 void
00953 _dbus_real_assert (dbus_bool_t condition,
00954 const char *condition_text,
00955 const char *file,
00956 int line,
00957 const char *func)
00958 {
00959 if (_DBUS_UNLIKELY (!condition))
00960 {
00961 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00962 _dbus_pid_for_log (), condition_text, file, line, func);
00963 _dbus_abort ();
00964 }
00965 }
00966
00977 void
00978 _dbus_real_assert_not_reached (const char *explanation,
00979 const char *file,
00980 int line)
00981 {
00982 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00983 file, line, _dbus_pid_for_log (), explanation);
00984 _dbus_abort ();
00985 }
00986 #endif
00987
00988 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00989 static dbus_bool_t
00990 run_failing_each_malloc (int n_mallocs,
00991 const char *description,
00992 DBusTestMemoryFunction func,
00993 void *data)
00994 {
00995 n_mallocs += 10;
00996
00997 while (n_mallocs >= 0)
00998 {
00999 _dbus_set_fail_alloc_counter (n_mallocs);
01000
01001 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
01002 description, n_mallocs,
01003 _dbus_get_fail_alloc_failures ());
01004
01005 if (!(* func) (data))
01006 return FALSE;
01007
01008 n_mallocs -= 1;
01009 }
01010
01011 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
01012
01013 return TRUE;
01014 }
01015
01029 dbus_bool_t
01030 _dbus_test_oom_handling (const char *description,
01031 DBusTestMemoryFunction func,
01032 void *data)
01033 {
01034 int approx_mallocs;
01035 const char *setting;
01036 int max_failures_to_try;
01037 int i;
01038
01039
01040
01041 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
01042
01043 _dbus_verbose ("Running once to count mallocs\n");
01044
01045 if (!(* func) (data))
01046 return FALSE;
01047
01048 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
01049
01050 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
01051 description, approx_mallocs);
01052
01053 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
01054 if (setting != NULL)
01055 {
01056 DBusString str;
01057 long v;
01058 _dbus_string_init_const (&str, setting);
01059 v = 4;
01060 if (!_dbus_string_parse_int (&str, 0, &v, NULL))
01061 _dbus_warn ("couldn't parse '%s' as integer\n", setting);
01062 max_failures_to_try = v;
01063 }
01064 else
01065 {
01066 max_failures_to_try = 4;
01067 }
01068
01069 if (max_failures_to_try < 1)
01070 {
01071 _dbus_verbose ("not testing OOM handling\n");
01072 return TRUE;
01073 }
01074
01075 i = setting ? max_failures_to_try - 1 : 1;
01076 while (i < max_failures_to_try)
01077 {
01078 _dbus_set_fail_alloc_failures (i);
01079 if (!run_failing_each_malloc (approx_mallocs, description, func, data))
01080 return FALSE;
01081 ++i;
01082 }
01083
01084 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
01085 description);
01086
01087 return TRUE;
01088 }
01089 #endif
01090