D-Bus  1.12.16
dbus-internals.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-internals.c random utility stuff (internal to D-Bus implementation)
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 
24 #include <config.h>
25 #include "dbus-internals.h"
26 #include "dbus-protocol.h"
27 #include "dbus-marshal-basic.h"
28 #include "dbus-test.h"
29 #include "dbus-valgrind-internal.h"
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
35 #include <windows.h>
36 #include <mbstring.h>
37 #endif
38 
184 const char *_dbus_no_memory_message = "Not enough memory";
185 
186 static dbus_bool_t warn_initted = FALSE;
187 static dbus_bool_t fatal_warnings = FALSE;
188 static dbus_bool_t fatal_warnings_on_check_failed = FALSE;
189 
190 static void
191 init_warnings(void)
192 {
193  if (!warn_initted)
194  {
195  const char *s;
196  s = _dbus_getenv ("DBUS_FATAL_WARNINGS");
197  if (s && *s)
198  {
199  if (*s == '0')
200  {
201  fatal_warnings = FALSE;
202  fatal_warnings_on_check_failed = FALSE;
203  }
204  else if (*s == '1')
205  {
206  fatal_warnings = TRUE;
207  fatal_warnings_on_check_failed = TRUE;
208  }
209  else
210  {
211  fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'",
212  s);
213  }
214  }
215 
216  warn_initted = TRUE;
217  }
218 }
219 
229 void
230 _dbus_warn (const char *format,
231  ...)
232 {
233  DBusSystemLogSeverity severity = DBUS_SYSTEM_LOG_WARNING;
234  va_list args;
235 
236  if (!warn_initted)
237  init_warnings ();
238 
239  if (fatal_warnings)
240  severity = DBUS_SYSTEM_LOG_ERROR;
241 
242  va_start (args, format);
243  _dbus_logv (severity, format, args);
244  va_end (args);
245 
246  if (fatal_warnings)
247  {
248  fflush (stderr);
249  _dbus_abort ();
250  }
251 }
252 
261 void
262 _dbus_warn_check_failed(const char *format,
263  ...)
264 {
265  DBusSystemLogSeverity severity = DBUS_SYSTEM_LOG_WARNING;
266  va_list args;
267 
268  if (!warn_initted)
269  init_warnings ();
270 
271  if (fatal_warnings_on_check_failed)
272  severity = DBUS_SYSTEM_LOG_ERROR;
273 
274  va_start (args, format);
275  _dbus_logv (severity, format, args);
276  va_end (args);
277 
278  if (fatal_warnings_on_check_failed)
279  {
280  fflush (stderr);
281  _dbus_abort ();
282  }
283 }
284 
285 #ifdef DBUS_ENABLE_VERBOSE_MODE
286 
287 static dbus_bool_t verbose_initted = FALSE;
288 static dbus_bool_t verbose = TRUE;
289 
290 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
291 static char module_name[1024];
292 #endif
293 
294 static inline void
295 _dbus_verbose_init (void)
296 {
297  if (!verbose_initted)
298  {
299  const char *p = _dbus_getenv ("DBUS_VERBOSE");
300  verbose = p != NULL && *p == '1';
301  verbose_initted = TRUE;
302 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
303  {
304  char *last_period, *last_slash;
305  GetModuleFileName(0,module_name,sizeof(module_name)-1);
306  last_period = _mbsrchr(module_name,'.');
307  if (last_period)
308  *last_period ='\0';
309  last_slash = _mbsrchr(module_name,'\\');
310  if (last_slash)
311  strcpy(module_name,last_slash+1);
312  strcat(module_name,": ");
313  }
314 #endif
315  }
316 }
317 
323 #ifdef DBUS_WIN
324 #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
325 #else
326 #define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
327 #endif
328 
333 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
334 {
335  int prefix = 0;
336  char *p = (char *)file + strlen(file);
337  int i = 0;
338 
339  for (;p >= file;p--)
340  {
341  if (DBUS_IS_DIR_SEPARATOR(*p))
342  {
343  if (++i >= level)
344  {
345  prefix = p-file+1;
346  break;
347  }
348  }
349  }
350 
351  return (char *)file+prefix;
352 }
353 
360 _dbus_is_verbose_real (void)
361 {
362  _dbus_verbose_init ();
363  return verbose;
364 }
365 
366 void _dbus_set_verbose (dbus_bool_t state)
367 {
368  verbose = state;
369 }
370 
371 dbus_bool_t _dbus_get_verbose (void)
372 {
373  return verbose;
374 }
375 
384 void
385 _dbus_verbose_real (
386 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
387  const char *file,
388  const int line,
389  const char *function,
390 #endif
391  const char *format,
392  ...)
393 {
394  va_list args;
395  static dbus_bool_t need_pid = TRUE;
396  int len;
397  long sec, usec;
398 
399  /* things are written a bit oddly here so that
400  * in the non-verbose case we just have the one
401  * conditional and return immediately.
402  */
403  if (!_dbus_is_verbose_real())
404  return;
405 
406 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING
407  /* Print out pid before the line */
408  if (need_pid)
409  {
410  _dbus_print_thread ();
411  }
412  _dbus_get_real_time (&sec, &usec);
413  fprintf (stderr, "%ld.%06ld ", sec, usec);
414 #endif
415 
416  /* Only print pid again if the next line is a new line */
417  len = strlen (format);
418  if (format[len-1] == '\n')
419  need_pid = TRUE;
420  else
421  need_pid = FALSE;
422 
423  va_start (args, format);
424 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
425  {
426  char buf[1024];
427  strcpy(buf,module_name);
428 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
429  sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
430 #endif
431  vsprintf (buf+strlen(buf),format, args);
432  va_end (args);
433  OutputDebugStringA(buf);
434  }
435 #else
436 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
437  fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
438 #endif
439 
440  vfprintf (stderr, format, args);
441  va_end (args);
442 
443  fflush (stderr);
444 #endif
445 }
446 
453 void
454 _dbus_verbose_reset_real (void)
455 {
456  verbose_initted = FALSE;
457 }
458 
459 void
460 _dbus_trace_ref (const char *obj_name,
461  void *obj,
462  int old_refcount,
463  int new_refcount,
464  const char *why,
465  const char *env_var,
466  int *enabled)
467 {
468  _dbus_assert (obj_name != NULL);
469  _dbus_assert (obj != NULL);
470  _dbus_assert (old_refcount >= -1);
471  _dbus_assert (new_refcount >= -1);
472 
473  if (old_refcount == -1)
474  {
475  _dbus_assert (new_refcount == -1);
476  }
477  else
478  {
479  _dbus_assert (new_refcount >= 0);
480  _dbus_assert (old_refcount >= 0);
481  _dbus_assert (old_refcount > 0 || new_refcount > 0);
482  }
483 
484  _dbus_assert (why != NULL);
485  _dbus_assert (env_var != NULL);
486  _dbus_assert (enabled != NULL);
487 
488  if (*enabled < 0)
489  {
490  const char *s = _dbus_getenv (env_var);
491 
492  *enabled = FALSE;
493 
494  if (s && *s)
495  {
496  if (*s == '0')
497  *enabled = FALSE;
498  else if (*s == '1')
499  *enabled = TRUE;
500  else
501  _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s);
502  }
503  }
504 
505  if (*enabled)
506  {
507  if (old_refcount == -1)
508  {
509  VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)",
510  obj_name, obj, why);
511  _dbus_verbose ("%s %p ref stolen (%s)\n",
512  obj_name, obj, why);
513  }
514  else
515  {
516  VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)",
517  obj_name, obj,
518  old_refcount, new_refcount, why);
519  _dbus_verbose ("%s %p %d -> %d refs (%s)\n",
520  obj_name, obj, old_refcount, new_refcount, why);
521  }
522  }
523 }
524 
525 #endif /* DBUS_ENABLE_VERBOSE_MODE */
526 
535 char*
536 _dbus_strdup (const char *str)
537 {
538  size_t len;
539  char *copy;
540 
541  if (str == NULL)
542  return NULL;
543 
544  len = strlen (str);
545 
546  copy = dbus_malloc (len + 1);
547  if (copy == NULL)
548  return NULL;
549 
550  memcpy (copy, str, len + 1);
551 
552  return copy;
553 }
554 
563 void*
564 _dbus_memdup (const void *mem,
565  size_t n_bytes)
566 {
567  void *copy;
568 
569  copy = dbus_malloc (n_bytes);
570  if (copy == NULL)
571  return NULL;
572 
573  memcpy (copy, mem, n_bytes);
574 
575  return copy;
576 }
577 
586 char**
587 _dbus_dup_string_array (const char **array)
588 {
589  int len;
590  int i;
591  char **copy;
592 
593  if (array == NULL)
594  return NULL;
595 
596  for (len = 0; array[len] != NULL; ++len)
597  ;
598 
599  copy = dbus_new0 (char*, len + 1);
600  if (copy == NULL)
601  return NULL;
602 
603  i = 0;
604  while (i < len)
605  {
606  copy[i] = _dbus_strdup (array[i]);
607  if (copy[i] == NULL)
608  {
609  dbus_free_string_array (copy);
610  return NULL;
611  }
612 
613  ++i;
614  }
615 
616  return copy;
617 }
618 
627 _dbus_string_array_contains (const char **array,
628  const char *str)
629 {
630  int i;
631 
632  i = 0;
633  while (array[i] != NULL)
634  {
635  if (strcmp (array[i], str) == 0)
636  return TRUE;
637  ++i;
638  }
639 
640  return FALSE;
641 }
642 
649 size_t
650 _dbus_string_array_length (const char **array)
651 {
652  size_t i;
653  for (i = 0; array[i]; i++) {}
654  return i;
655 }
656 
657 
668  DBusError *error)
669 {
670  DBusError rand_error;
671  long now;
672 
673  dbus_error_init (&rand_error);
674 
675  /* don't use monotonic time because the UUID may be saved to disk, e.g.
676  * it may persist across reboots
677  */
678  _dbus_get_real_time (&now, NULL);
679 
680  uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
681 
683  DBUS_UUID_LENGTH_BYTES - 4,
684  &rand_error))
685  {
686  dbus_set_error (error, rand_error.name,
687  "Failed to generate UUID: %s", rand_error.message);
688  dbus_error_free (&rand_error);
689  return FALSE;
690  }
691 
692  return TRUE;
693 }
694 
704  DBusString *encoded)
705 {
706  DBusString binary;
707  _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
708  return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
709 }
710 
711 static dbus_bool_t
712 _dbus_read_uuid_file_without_creating (const DBusString *filename,
713  DBusGUID *uuid,
714  DBusError *error)
715 {
716  DBusString contents;
717  DBusString decoded;
718  int end;
719 
720  if (!_dbus_string_init (&contents))
721  {
722  _DBUS_SET_OOM (error);
723  return FALSE;
724  }
725 
726  if (!_dbus_string_init (&decoded))
727  {
728  _dbus_string_free (&contents);
729  _DBUS_SET_OOM (error);
730  return FALSE;
731  }
732 
733  if (!_dbus_file_get_contents (&contents, filename, error))
734  goto error;
735 
736  _dbus_string_chop_white (&contents);
737 
738  if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
739  {
741  "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
742  _dbus_string_get_const_data (filename),
743  DBUS_UUID_LENGTH_HEX,
744  _dbus_string_get_length (&contents));
745  goto error;
746  }
747 
748  if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
749  {
750  _DBUS_SET_OOM (error);
751  goto error;
752  }
753 
754  if (end == 0)
755  {
757  "UUID file '%s' contains invalid hex data",
758  _dbus_string_get_const_data (filename));
759  goto error;
760  }
761 
762  if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
763  {
765  "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
766  _dbus_string_get_const_data (filename),
767  _dbus_string_get_length (&decoded),
768  DBUS_UUID_LENGTH_BYTES);
769  goto error;
770  }
771 
772  _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
773 
774  _dbus_string_free (&decoded);
775  _dbus_string_free (&contents);
776 
777  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
778 
779  return TRUE;
780 
781  error:
782  _DBUS_ASSERT_ERROR_IS_SET (error);
783  _dbus_string_free (&contents);
784  _dbus_string_free (&decoded);
785  return FALSE;
786 }
787 
798  const DBusGUID *uuid,
799  DBusError *error)
800 {
801  DBusString encoded;
802 
803  if (!_dbus_string_init (&encoded))
804  {
805  _DBUS_SET_OOM (error);
806  return FALSE;
807  }
808 
809  if (!_dbus_uuid_encode (uuid, &encoded))
810  {
811  _DBUS_SET_OOM (error);
812  goto error;
813  }
814 
815  if (!_dbus_string_append_byte (&encoded, '\n'))
816  {
817  _DBUS_SET_OOM (error);
818  goto error;
819  }
820 
821  if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
822  goto error;
823 
824  _dbus_string_free (&encoded);
825 
826  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
827  return TRUE;
828 
829  error:
830  _DBUS_ASSERT_ERROR_IS_SET (error);
831  _dbus_string_free (&encoded);
832  return FALSE;
833 }
834 
847  DBusGUID *uuid,
848  dbus_bool_t create_if_not_found,
849  DBusError *error)
850 {
851  DBusError read_error = DBUS_ERROR_INIT;
852 
853  if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
854  return TRUE;
855 
856  if (!create_if_not_found)
857  {
858  dbus_move_error (&read_error, error);
859  return FALSE;
860  }
861 
862  /* If the file exists and contains junk, we want to keep that error
863  * message instead of overwriting it with a "file exists" error
864  * message when we try to write
865  */
867  {
868  dbus_move_error (&read_error, error);
869  return FALSE;
870  }
871  else
872  {
873  dbus_error_free (&read_error);
874 
875  if (!_dbus_generate_uuid (uuid, error))
876  return FALSE;
877 
878  return _dbus_write_uuid_file (filename, uuid, error);
879  }
880 }
881 
882 /* Protected by _DBUS_LOCK (machine_uuid) */
883 static int machine_uuid_initialized_generation = 0;
884 static DBusGUID machine_uuid;
885 
899  DBusError *error)
900 {
901  dbus_bool_t ok = TRUE;
902 
903  if (!_DBUS_LOCK (machine_uuid))
904  {
905  _DBUS_SET_OOM (error);
906  return FALSE;
907  }
908 
909  if (machine_uuid_initialized_generation != _dbus_current_generation)
910  {
911  if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE, error))
912  ok = FALSE;
913  }
914 
915  if (ok)
916  {
917  if (!_dbus_uuid_encode (&machine_uuid, uuid_str))
918  {
919  ok = FALSE;
920  _DBUS_SET_OOM (error);
921  }
922  }
923 
924  _DBUS_UNLOCK (machine_uuid);
925 
926  return ok;
927 }
928 
929 #ifndef DBUS_DISABLE_CHECKS
930 void
931 _dbus_warn_return_if_fail (const char *function,
932  const char *assertion,
933  const char *file,
934  int line)
935 {
937  "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
938  "This is normally a bug in some application using the D-Bus library.\n",
939  function, assertion, file, line);
940 }
941 #endif
942 
943 #ifndef DBUS_DISABLE_ASSERT
944 
956 void
958  const char *condition_text,
959  const char *file,
960  int line,
961  const char *func)
962 {
963  if (_DBUS_UNLIKELY (!condition))
964  {
965  _dbus_warn ("assertion failed \"%s\" file \"%s\" line %d function %s",
966  condition_text, file, line, func);
967  _dbus_abort ();
968  }
969 }
970 
981 void
982 _dbus_real_assert_not_reached (const char *explanation,
983  const char *file,
984  int line)
985 {
986  _dbus_warn ("File \"%s\" line %d should not have been reached: %s",
987  file, line, explanation);
988  _dbus_abort ();
989 }
990 #endif /* DBUS_DISABLE_ASSERT */
991 
992 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
993 static dbus_bool_t
994 run_failing_each_malloc (int n_mallocs,
995  const char *description,
996  DBusTestMemoryFunction func,
997  void *data)
998 {
999  n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */
1000 
1001  while (n_mallocs >= 0)
1002  {
1003  _dbus_set_fail_alloc_counter (n_mallocs);
1004 
1005  _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
1006  description, n_mallocs,
1007  _dbus_get_fail_alloc_failures ());
1008 
1009  if (!(* func) (data))
1010  return FALSE;
1011 
1012  n_mallocs -= 1;
1013  }
1014 
1015  _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
1016 
1017  return TRUE;
1018 }
1019 
1034 _dbus_test_oom_handling (const char *description,
1035  DBusTestMemoryFunction func,
1036  void *data)
1037 {
1038  int approx_mallocs;
1039  const char *setting;
1040  int max_failures_to_try;
1041  int i;
1042 
1043  /* Run once to see about how many mallocs are involved */
1044 
1045  _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
1046 
1047  _dbus_verbose ("Running once to count mallocs\n");
1048 
1049  if (!(* func) (data))
1050  return FALSE;
1051 
1052  approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
1053 
1054  _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
1055  description, approx_mallocs);
1056 
1057  setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
1058  if (setting != NULL)
1059  {
1060  DBusString str;
1061  long v;
1062  _dbus_string_init_const (&str, setting);
1063  v = 4;
1064  if (!_dbus_string_parse_int (&str, 0, &v, NULL))
1065  _dbus_warn ("couldn't parse '%s' as integer\n", setting);
1066  max_failures_to_try = v;
1067  }
1068  else
1069  {
1070  max_failures_to_try = 4;
1071  }
1072 
1073  if (max_failures_to_try < 1)
1074  {
1075  _dbus_verbose ("not testing OOM handling\n");
1076  return TRUE;
1077  }
1078 
1079  i = setting ? max_failures_to_try - 1 : 1;
1080  while (i < max_failures_to_try)
1081  {
1082  _dbus_set_fail_alloc_failures (i);
1083  if (!run_failing_each_malloc (approx_mallocs, description, func, data))
1084  return FALSE;
1085  ++i;
1086  }
1087 
1088  _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
1089  description);
1090 
1091  return TRUE;
1092 }
1093 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
1094