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
00199 const char *_dbus_no_memory_message = "Not enough memory";
00200
00201 static dbus_bool_t warn_initted = FALSE;
00202 static dbus_bool_t fatal_warnings = FALSE;
00203 static dbus_bool_t fatal_warnings_on_check_failed = TRUE;
00204
00205 static void
00206 init_warnings(void)
00207 {
00208 if (!warn_initted)
00209 {
00210 const char *s;
00211 s = _dbus_getenv ("DBUS_FATAL_WARNINGS");
00212 if (s && *s)
00213 {
00214 if (*s == '0')
00215 {
00216 fatal_warnings = FALSE;
00217 fatal_warnings_on_check_failed = FALSE;
00218 }
00219 else if (*s == '1')
00220 {
00221 fatal_warnings = TRUE;
00222 fatal_warnings_on_check_failed = TRUE;
00223 }
00224 else
00225 {
00226 fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'",
00227 s);
00228 }
00229 }
00230
00231 warn_initted = TRUE;
00232 }
00233 }
00234
00244 void
00245 _dbus_warn (const char *format,
00246 ...)
00247 {
00248 va_list args;
00249
00250 if (!warn_initted)
00251 init_warnings ();
00252
00253 va_start (args, format);
00254 vfprintf (stderr, format, args);
00255 va_end (args);
00256
00257 if (fatal_warnings)
00258 {
00259 fflush (stderr);
00260 _dbus_abort ();
00261 }
00262 }
00263
00272 void
00273 _dbus_warn_check_failed(const char *format,
00274 ...)
00275 {
00276 va_list args;
00277
00278 if (!warn_initted)
00279 init_warnings ();
00280
00281 fprintf (stderr, "process %lu: ", _dbus_pid_for_log ());
00282
00283 va_start (args, format);
00284 vfprintf (stderr, format, args);
00285 va_end (args);
00286
00287 if (fatal_warnings_on_check_failed)
00288 {
00289 fflush (stderr);
00290 _dbus_abort ();
00291 }
00292 }
00293
00294 #ifdef DBUS_ENABLE_VERBOSE_MODE
00295
00296 static dbus_bool_t verbose_initted = FALSE;
00297 static dbus_bool_t verbose = TRUE;
00298
00300 #define PTHREAD_IN_VERBOSE 0
00301 #if PTHREAD_IN_VERBOSE
00302 #include <pthread.h>
00303 #endif
00304
00305 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00306 static char module_name[1024];
00307 #endif
00308
00309 static inline void
00310 _dbus_verbose_init (void)
00311 {
00312 if (!verbose_initted)
00313 {
00314 const char *p = _dbus_getenv ("DBUS_VERBOSE");
00315 verbose = p != NULL && *p == '1';
00316 verbose_initted = TRUE;
00317 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00318 {
00319 char *last_period, *last_slash;
00320 GetModuleFileName(0,module_name,sizeof(module_name)-1);
00321 last_period = _mbsrchr(module_name,'.');
00322 if (last_period)
00323 *last_period ='\0';
00324 last_slash = _mbsrchr(module_name,'\\');
00325 if (last_slash)
00326 strcpy(module_name,last_slash+1);
00327 strcat(module_name,": ");
00328 }
00329 #endif
00330 }
00331 }
00332
00338 #ifdef DBUS_WIN
00339 #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
00340 #else
00341 #define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
00342 #endif
00343
00348 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
00349 {
00350 static int prefix = -1;
00351
00352 if (prefix == -1)
00353 {
00354 char *p = (char *)file + strlen(file);
00355 int i = 0;
00356 prefix = 0;
00357 for (;p >= file;p--)
00358 {
00359 if (DBUS_IS_DIR_SEPARATOR(*p))
00360 {
00361 if (++i >= level)
00362 {
00363 prefix = p-file+1;
00364 break;
00365 }
00366 }
00367 }
00368 }
00369 return (char *)file+prefix;
00370 }
00371
00377 dbus_bool_t
00378 _dbus_is_verbose_real (void)
00379 {
00380 _dbus_verbose_init ();
00381 return verbose;
00382 }
00383
00392 void
00393 _dbus_verbose_real (
00394 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00395 const char *file,
00396 const int line,
00397 const char *function,
00398 #endif
00399 const char *format,
00400 ...)
00401 {
00402 va_list args;
00403 static dbus_bool_t need_pid = TRUE;
00404 int len;
00405
00406
00407
00408
00409
00410 if (!_dbus_is_verbose_real())
00411 return;
00412
00413 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING
00414
00415 if (need_pid)
00416 {
00417 #if PTHREAD_IN_VERBOSE
00418 fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());
00419 #else
00420 fprintf (stderr, "%lu: ", _dbus_pid_for_log ());
00421 #endif
00422 }
00423 #endif
00424
00425
00426 len = strlen (format);
00427 if (format[len-1] == '\n')
00428 need_pid = TRUE;
00429 else
00430 need_pid = FALSE;
00431
00432 va_start (args, format);
00433 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00434 {
00435 char buf[1024];
00436 strcpy(buf,module_name);
00437 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00438 sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00439 #endif
00440 vsprintf (buf+strlen(buf),format, args);
00441 va_end (args);
00442 OutputDebugStringA(buf);
00443 }
00444 #else
00445 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00446 fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00447 #endif
00448
00449 vfprintf (stderr, format, args);
00450 va_end (args);
00451
00452 fflush (stderr);
00453 #endif
00454 }
00455
00462 void
00463 _dbus_verbose_reset_real (void)
00464 {
00465 verbose_initted = FALSE;
00466 }
00467
00468 void
00469 _dbus_trace_ref (const char *obj_name,
00470 void *obj,
00471 int old_refcount,
00472 int new_refcount,
00473 const char *why,
00474 const char *env_var,
00475 int *enabled)
00476 {
00477 _dbus_assert (obj_name != NULL);
00478 _dbus_assert (obj != NULL);
00479 _dbus_assert (old_refcount >= -1);
00480 _dbus_assert (new_refcount >= -1);
00481
00482 if (old_refcount == -1)
00483 {
00484 _dbus_assert (new_refcount == -1);
00485 }
00486 else
00487 {
00488 _dbus_assert (new_refcount >= 0);
00489 _dbus_assert (old_refcount >= 0);
00490 _dbus_assert (old_refcount > 0 || new_refcount > 0);
00491 }
00492
00493 _dbus_assert (why != NULL);
00494 _dbus_assert (env_var != NULL);
00495 _dbus_assert (enabled != NULL);
00496
00497 if (*enabled < 0)
00498 {
00499 const char *s = _dbus_getenv (env_var);
00500
00501 *enabled = FALSE;
00502
00503 if (s && *s)
00504 {
00505 if (*s == '0')
00506 *enabled = FALSE;
00507 else if (*s == '1')
00508 *enabled = TRUE;
00509 else
00510 _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s);
00511 }
00512 }
00513
00514 if (*enabled)
00515 {
00516 if (old_refcount == -1)
00517 {
00518 VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)",
00519 obj_name, obj, why);
00520 _dbus_verbose ("%s %p ref stolen (%s)",
00521 obj_name, obj, why);
00522 }
00523 else
00524 {
00525 VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)",
00526 obj_name, obj,
00527 old_refcount, new_refcount, why);
00528 _dbus_verbose ("%s %p %d -> %d refs (%s)",
00529 obj_name, obj, old_refcount, new_refcount, why);
00530 }
00531 }
00532 }
00533
00534 #endif
00535
00544 char*
00545 _dbus_strdup (const char *str)
00546 {
00547 size_t len;
00548 char *copy;
00549
00550 if (str == NULL)
00551 return NULL;
00552
00553 len = strlen (str);
00554
00555 copy = dbus_malloc (len + 1);
00556 if (copy == NULL)
00557 return NULL;
00558
00559 memcpy (copy, str, len + 1);
00560
00561 return copy;
00562 }
00563
00572 void*
00573 _dbus_memdup (const void *mem,
00574 size_t n_bytes)
00575 {
00576 void *copy;
00577
00578 copy = dbus_malloc (n_bytes);
00579 if (copy == NULL)
00580 return NULL;
00581
00582 memcpy (copy, mem, n_bytes);
00583
00584 return copy;
00585 }
00586
00595 char**
00596 _dbus_dup_string_array (const char **array)
00597 {
00598 int len;
00599 int i;
00600 char **copy;
00601
00602 if (array == NULL)
00603 return NULL;
00604
00605 for (len = 0; array[len] != NULL; ++len)
00606 ;
00607
00608 copy = dbus_new0 (char*, len + 1);
00609 if (copy == NULL)
00610 return NULL;
00611
00612 i = 0;
00613 while (i < len)
00614 {
00615 copy[i] = _dbus_strdup (array[i]);
00616 if (copy[i] == NULL)
00617 {
00618 dbus_free_string_array (copy);
00619 return NULL;
00620 }
00621
00622 ++i;
00623 }
00624
00625 return copy;
00626 }
00627
00635 dbus_bool_t
00636 _dbus_string_array_contains (const char **array,
00637 const char *str)
00638 {
00639 int i;
00640
00641 i = 0;
00642 while (array[i] != NULL)
00643 {
00644 if (strcmp (array[i], str) == 0)
00645 return TRUE;
00646 ++i;
00647 }
00648
00649 return FALSE;
00650 }
00651
00658 void
00659 _dbus_generate_uuid (DBusGUID *uuid)
00660 {
00661 long now;
00662
00663
00664
00665
00666 _dbus_get_real_time (&now, NULL);
00667
00668 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00669
00670 _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4);
00671 }
00672
00680 dbus_bool_t
00681 _dbus_uuid_encode (const DBusGUID *uuid,
00682 DBusString *encoded)
00683 {
00684 DBusString binary;
00685 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00686 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00687 }
00688
00689 static dbus_bool_t
00690 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00691 DBusGUID *uuid,
00692 DBusError *error)
00693 {
00694 DBusString contents;
00695 DBusString decoded;
00696 int end;
00697
00698 if (!_dbus_string_init (&contents))
00699 {
00700 _DBUS_SET_OOM (error);
00701 return FALSE;
00702 }
00703
00704 if (!_dbus_string_init (&decoded))
00705 {
00706 _dbus_string_free (&contents);
00707 _DBUS_SET_OOM (error);
00708 return FALSE;
00709 }
00710
00711 if (!_dbus_file_get_contents (&contents, filename, error))
00712 goto error;
00713
00714 _dbus_string_chop_white (&contents);
00715
00716 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00717 {
00718 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00719 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00720 _dbus_string_get_const_data (filename),
00721 DBUS_UUID_LENGTH_HEX,
00722 _dbus_string_get_length (&contents));
00723 goto error;
00724 }
00725
00726 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00727 {
00728 _DBUS_SET_OOM (error);
00729 goto error;
00730 }
00731
00732 if (end == 0)
00733 {
00734 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00735 "UUID file '%s' contains invalid hex data",
00736 _dbus_string_get_const_data (filename));
00737 goto error;
00738 }
00739
00740 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00741 {
00742 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00743 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00744 _dbus_string_get_const_data (filename),
00745 _dbus_string_get_length (&decoded),
00746 DBUS_UUID_LENGTH_BYTES);
00747 goto error;
00748 }
00749
00750 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00751
00752 _dbus_string_free (&decoded);
00753 _dbus_string_free (&contents);
00754
00755 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00756
00757 return TRUE;
00758
00759 error:
00760 _DBUS_ASSERT_ERROR_IS_SET (error);
00761 _dbus_string_free (&contents);
00762 _dbus_string_free (&decoded);
00763 return FALSE;
00764 }
00765
00766 static dbus_bool_t
00767 _dbus_create_uuid_file_exclusively (const DBusString *filename,
00768 DBusGUID *uuid,
00769 DBusError *error)
00770 {
00771 DBusString encoded;
00772
00773 if (!_dbus_string_init (&encoded))
00774 {
00775 _DBUS_SET_OOM (error);
00776 return FALSE;
00777 }
00778
00779 _dbus_generate_uuid (uuid);
00780
00781 if (!_dbus_uuid_encode (uuid, &encoded))
00782 {
00783 _DBUS_SET_OOM (error);
00784 goto error;
00785 }
00786
00787 if (!_dbus_string_append_byte (&encoded, '\n'))
00788 {
00789 _DBUS_SET_OOM (error);
00790 goto error;
00791 }
00792
00793 if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
00794 goto error;
00795
00796 _dbus_string_free (&encoded);
00797
00798 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00799 return TRUE;
00800
00801 error:
00802 _DBUS_ASSERT_ERROR_IS_SET (error);
00803 _dbus_string_free (&encoded);
00804 return FALSE;
00805 }
00806
00817 dbus_bool_t
00818 _dbus_read_uuid_file (const DBusString *filename,
00819 DBusGUID *uuid,
00820 dbus_bool_t create_if_not_found,
00821 DBusError *error)
00822 {
00823 DBusError read_error = DBUS_ERROR_INIT;
00824
00825 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00826 return TRUE;
00827
00828 if (!create_if_not_found)
00829 {
00830 dbus_move_error (&read_error, error);
00831 return FALSE;
00832 }
00833
00834
00835
00836
00837
00838 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00839 {
00840 dbus_move_error (&read_error, error);
00841 return FALSE;
00842 }
00843 else
00844 {
00845 dbus_error_free (&read_error);
00846 return _dbus_create_uuid_file_exclusively (filename, uuid, error);
00847 }
00848 }
00849
00850 _DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
00851 static int machine_uuid_initialized_generation = 0;
00852 static DBusGUID machine_uuid;
00853
00864 dbus_bool_t
00865 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
00866 {
00867 dbus_bool_t ok;
00868
00869 _DBUS_LOCK (machine_uuid);
00870 if (machine_uuid_initialized_generation != _dbus_current_generation)
00871 {
00872 DBusError error = DBUS_ERROR_INIT;
00873
00874 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00875 &error))
00876 {
00877 #ifndef DBUS_BUILD_TESTS
00878
00879
00880
00881
00882 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00883 "See the manual page for dbus-uuidgen to correct this issue.\n",
00884 error.message);
00885 #endif
00886
00887 dbus_error_free (&error);
00888
00889 _dbus_generate_uuid (&machine_uuid);
00890 }
00891 }
00892
00893 ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
00894
00895 _DBUS_UNLOCK (machine_uuid);
00896
00897 return ok;
00898 }
00899
00900 #ifndef DBUS_DISABLE_CHECKS
00901
00902 const char *_dbus_return_if_fail_warning_format =
00903 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00904 "This is normally a bug in some application using the D-Bus library.\n";
00905 #endif
00906
00907 #ifndef DBUS_DISABLE_ASSERT
00908
00920 void
00921 _dbus_real_assert (dbus_bool_t condition,
00922 const char *condition_text,
00923 const char *file,
00924 int line,
00925 const char *func)
00926 {
00927 if (_DBUS_UNLIKELY (!condition))
00928 {
00929 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00930 _dbus_pid_for_log (), condition_text, file, line, func);
00931 _dbus_abort ();
00932 }
00933 }
00934
00945 void
00946 _dbus_real_assert_not_reached (const char *explanation,
00947 const char *file,
00948 int line)
00949 {
00950 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00951 file, line, _dbus_pid_for_log (), explanation);
00952 _dbus_abort ();
00953 }
00954 #endif
00955
00956 #ifdef DBUS_BUILD_TESTS
00957 static dbus_bool_t
00958 run_failing_each_malloc (int n_mallocs,
00959 const char *description,
00960 DBusTestMemoryFunction func,
00961 void *data)
00962 {
00963 n_mallocs += 10;
00964
00965 while (n_mallocs >= 0)
00966 {
00967 _dbus_set_fail_alloc_counter (n_mallocs);
00968
00969 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
00970 description, n_mallocs,
00971 _dbus_get_fail_alloc_failures ());
00972
00973 if (!(* func) (data))
00974 return FALSE;
00975
00976 n_mallocs -= 1;
00977 }
00978
00979 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00980
00981 return TRUE;
00982 }
00983
00997 dbus_bool_t
00998 _dbus_test_oom_handling (const char *description,
00999 DBusTestMemoryFunction func,
01000 void *data)
01001 {
01002 int approx_mallocs;
01003 const char *setting;
01004 int max_failures_to_try;
01005 int i;
01006
01007
01008
01009 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
01010
01011 _dbus_verbose ("Running once to count mallocs\n");
01012
01013 if (!(* func) (data))
01014 return FALSE;
01015
01016 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
01017
01018 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
01019 description, approx_mallocs);
01020
01021 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
01022 if (setting != NULL)
01023 {
01024 DBusString str;
01025 long v;
01026 _dbus_string_init_const (&str, setting);
01027 v = 4;
01028 if (!_dbus_string_parse_int (&str, 0, &v, NULL))
01029 _dbus_warn ("couldn't parse '%s' as integer\n", setting);
01030 max_failures_to_try = v;
01031 }
01032 else
01033 {
01034 max_failures_to_try = 4;
01035 }
01036
01037 i = setting ? max_failures_to_try - 1 : 1;
01038 while (i < max_failures_to_try)
01039 {
01040 _dbus_set_fail_alloc_failures (i);
01041 if (!run_failing_each_malloc (approx_mallocs, description, func, data))
01042 return FALSE;
01043 ++i;
01044 }
01045
01046 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
01047 description);
01048
01049 return TRUE;
01050 }
01051 #endif
01052