X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-message-util.c;h=f785952039ec9cd30b79c135034789449b05e245;hb=67f9cca382df0d03adfe6b619aa613d103fa77f6;hp=5d503a980c178f94fc870a2f6f2d11b2581c4b23;hpb=9d21554dd3b560952cd5aa607c4ec07898c0b260;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c index 5d503a9..f785952 100644 --- a/dbus/dbus-message-util.c +++ b/dbus/dbus-message-util.c @@ -1,4 +1,4 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-message-util.c Would be in dbus-message.c, but only used by bus/tests * * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. @@ -18,15 +18,27 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include #include "dbus-internals.h" #include "dbus-test.h" #include "dbus-message-private.h" #include "dbus-marshal-recursive.h" #include "dbus-string.h" +#ifdef HAVE_UNIX_FD_PASSING +#include "dbus-sysdeps-unix.h" +#endif + +#ifdef __linux__ +/* Necessary for the Linux-specific fd leak checking code only */ +#include +#include +#include +#include +#endif /** * @addtogroup DBusMessage @@ -40,10 +52,6 @@ * basic type may be read with this function. See * dbus_message_get_args() for more details. * - * @todo this is static for now because there's no corresponding - * iter_append_args() and I'm not sure we need this function to be - * public since dbus_message_get_args() is what you usually want - * * @param iter the message iterator * @param error error to be filled in on failure * @param first_arg_type the first argument type @@ -78,6 +86,45 @@ dbus_message_iter_get_args (DBusMessageIter *iter, #include #include +static int validities_seen[DBUS_VALIDITY_LAST + _DBUS_NEGATIVE_VALIDITY_COUNT]; + +static void +reset_validities_seen (void) +{ + int i; + i = 0; + while (i < _DBUS_N_ELEMENTS (validities_seen)) + { + validities_seen[i] = 0; + ++i; + } +} + +static void +record_validity_seen (DBusValidity validity) +{ + validities_seen[validity + _DBUS_NEGATIVE_VALIDITY_COUNT] += 1; +} + +static void +print_validities_seen (dbus_bool_t not_seen) +{ + int i; + i = 0; + while (i < _DBUS_N_ELEMENTS (validities_seen)) + { + if ((i - _DBUS_NEGATIVE_VALIDITY_COUNT) == DBUS_VALIDITY_UNKNOWN || + (i - _DBUS_NEGATIVE_VALIDITY_COUNT) == DBUS_INVALID_FOR_UNKNOWN_REASON) + ; + else if ((not_seen && validities_seen[i] == 0) || + (!not_seen && validities_seen[i] > 0)) + printf ("validity %3d seen %d times\n", + i - _DBUS_NEGATIVE_VALIDITY_COUNT, + validities_seen[i]); + ++i; + } +} + static void check_memleaks (void) { @@ -91,6 +138,111 @@ check_memleaks (void) } } +#ifdef __linux__ +struct DBusInitialFDs { + fd_set set; +}; +#endif + +DBusInitialFDs * +_dbus_check_fdleaks_enter (void) +{ +#ifdef __linux__ + DIR *d; + DBusInitialFDs *fds; + + /* this is plain malloc so it won't interfere with leak checking */ + fds = malloc (sizeof (DBusInitialFDs)); + _dbus_assert (fds != NULL); + + /* This works on Linux only */ + + if ((d = opendir ("/proc/self/fd"))) + { + struct dirent *de; + + while ((de = readdir(d))) + { + long l; + char *e = NULL; + int fd; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol (de->d_name, &e, 10); + _dbus_assert (errno == 0 && e && !*e); + + fd = (int) l; + + if (fd < 3) + continue; + + if (fd == dirfd (d)) + continue; + + FD_SET (fd, &fds->set); + } + + closedir (d); + } + + return fds; +#else + return NULL; +#endif +} + +void +_dbus_check_fdleaks_leave (DBusInitialFDs *fds) +{ +#ifdef __linux__ + DIR *d; + + /* This works on Linux only */ + + if ((d = opendir ("/proc/self/fd"))) + { + struct dirent *de; + + while ((de = readdir(d))) + { + long l; + char *e = NULL; + int fd; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol (de->d_name, &e, 10); + _dbus_assert (errno == 0 && e && !*e); + + fd = (int) l; + + if (fd < 3) + continue; + + if (fd == dirfd (d)) + continue; + + if (FD_ISSET (fd, &fds->set)) + continue; + + _dbus_warn ("file descriptor %i leaked in %s.\n", fd, __FILE__); + _dbus_assert_not_reached ("fdleaks"); + } + + closedir (d); + } + + free (fds); +#else + _dbus_assert (fds == NULL); +#endif +} + static dbus_bool_t check_have_valid_message (DBusMessageLoader *loader) { @@ -130,6 +282,8 @@ check_have_valid_message (DBusMessageLoader *loader) goto failed; #endif + record_validity_seen (DBUS_VALID); + retval = TRUE; failed: @@ -153,6 +307,8 @@ check_invalid_message (DBusMessageLoader *loader, goto failed; } + record_validity_seen (loader->corruption_reason); + if (expected_validity != DBUS_INVALID_FOR_UNKNOWN_REASON && loader->corruption_reason != expected_validity) { @@ -190,6 +346,7 @@ check_incomplete_message (DBusMessageLoader *loader) goto failed; } + record_validity_seen (DBUS_VALID_BUT_INCOMPLETE); retval = TRUE; failed: @@ -212,8 +369,12 @@ check_loader_results (DBusMessageLoader *loader, else if (expected_validity == DBUS_VALIDITY_UNKNOWN) { /* here we just know we didn't segfault and that was the - * only test + * only test. Also, we record that we got coverage + * for the validity reason. */ + if (_dbus_message_loader_get_is_corrupted (loader)) + record_validity_seen (loader->corruption_reason); + return TRUE; } else @@ -232,12 +393,11 @@ dbus_internal_do_not_use_load_message_file (const DBusString *filename, DBusString *data) { dbus_bool_t retval; - DBusError error; - + DBusError error = DBUS_ERROR_INIT; + retval = FALSE; _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename)); - dbus_error_init (&error); if (!_dbus_file_get_contents (data, filename, &error)) { _dbus_warn ("Could not load message file %s: %s\n", @@ -406,7 +566,7 @@ process_test_subdir (const DBusString *test_base_dir, DBusString filename; DBusDirIter *dir; dbus_bool_t retval; - DBusError error; + DBusError error = DBUS_ERROR_INIT; retval = FALSE; dir = NULL; @@ -427,7 +587,6 @@ process_test_subdir (const DBusString *test_base_dir, if (!_dbus_string_init (&filename)) _dbus_assert_not_reached ("didn't allocate filename string\n"); - dbus_error_init (&error); dir = _dbus_directory_open (&test_directory, &error); if (dir == NULL) { @@ -460,8 +619,8 @@ process_test_subdir (const DBusString *test_base_dir, { if (_dbus_string_ends_with_c_str (&filename, ".message")) { - _dbus_warn ("Could not load %s, message builder language no longer supported\n", - _dbus_string_get_const_data (&filename)); + printf ("SKIP: Could not load %s, message builder language no longer supported\n", + _dbus_string_get_const_data (&filename)); } _dbus_verbose ("Skipping non-.message file %s\n", @@ -591,6 +750,8 @@ message_iter_test (DBusMessage *message) DBusMessageIter iter, array, array2; const char *v_STRING; double v_DOUBLE; + dbus_int16_t v_INT16; + dbus_uint16_t v_UINT16; dbus_int32_t v_INT32; dbus_uint32_t v_UINT32; #ifdef DBUS_HAVE_INT64 @@ -655,7 +816,9 @@ static void verify_test_message (DBusMessage *message) { DBusMessageIter iter; - DBusError error; + DBusError error = DBUS_ERROR_INIT; + dbus_int16_t our_int16; + dbus_uint16_t our_uint16; dbus_int32_t our_int; dbus_uint32_t our_uint; const char *our_str; @@ -663,7 +826,7 @@ verify_test_message (DBusMessage *message) double v_DOUBLE; dbus_bool_t our_bool; unsigned char our_byte_1, our_byte_2; - const dbus_int32_t *our_uint32_array = (void*)0xdeadbeef; + const dbus_uint32_t *our_uint32_array = (void*)0xdeadbeef; int our_uint32_array_len; dbus_int32_t *our_int32_array = (void*)0xdeadbeef; int our_int32_array_len; @@ -681,11 +844,14 @@ verify_test_message (DBusMessage *message) int our_byte_array_len; const dbus_bool_t *our_boolean_array = (void*)0xdeadbeef; int our_boolean_array_len; + char **our_string_array; + int our_string_array_len; dbus_message_iter_init (message, &iter); - dbus_error_init (&error); if (!dbus_message_iter_get_args (&iter, &error, + DBUS_TYPE_INT16, &our_int16, + DBUS_TYPE_UINT16, &our_uint16, DBUS_TYPE_INT32, &our_int, DBUS_TYPE_UINT32, &our_uint, #ifdef DBUS_HAVE_INT64 @@ -713,6 +879,8 @@ verify_test_message (DBusMessage *message) &our_byte_array, &our_byte_array_len, DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &our_boolean_array, &our_boolean_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, + &our_string_array, &our_string_array_len, 0)) { _dbus_warn ("error: %s - %s\n", error.name, @@ -720,6 +888,12 @@ verify_test_message (DBusMessage *message) _dbus_assert_not_reached ("Could not get arguments"); } + if (our_int16 != -0x123) + _dbus_assert_not_reached ("16-bit integers differ!"); + + if (our_uint16 != 0x123) + _dbus_assert_not_reached ("16-bit uints differ!"); + if (our_int != -0x12345678) _dbus_assert_not_reached ("integers differ!"); @@ -814,6 +988,17 @@ verify_test_message (DBusMessage *message) our_boolean_array[4] != FALSE) _dbus_assert_not_reached ("bool array had wrong values"); + if (our_string_array_len != 4) + _dbus_assert_not_reached ("string array was wrong length"); + + if (strcmp (our_string_array[0], "Foo") != 0 || + strcmp (our_string_array[1], "bar") != 0 || + strcmp (our_string_array[2], "") != 0 || + strcmp (our_string_array[3], "woo woo woo woo") != 0) + _dbus_assert_not_reached ("string array had wrong values"); + + dbus_free_string_array (our_string_array); + if (dbus_message_iter_next (&iter)) _dbus_assert_not_reached ("Didn't reach end of arguments"); } @@ -827,7 +1012,7 @@ verify_test_message (DBusMessage *message) dbus_bool_t _dbus_message_test (const char *test_data_dir) { - DBusMessage *message; + DBusMessage *message, *message_without_unix_fds; DBusMessageLoader *loader; int i; const char *data; @@ -836,14 +1021,14 @@ _dbus_message_test (const char *test_data_dir) const char *name2; const dbus_uint32_t our_uint32_array[] = { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; - const dbus_uint32_t our_int32_array[] = + const dbus_int32_t our_int32_array[] = { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array; const dbus_int32_t *v_ARRAY_INT32 = our_int32_array; #ifdef DBUS_HAVE_INT64 const dbus_uint64_t our_uint64_array[] = { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; - const dbus_uint64_t our_int64_array[] = + const dbus_int64_t our_int64_array[] = { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array; const dbus_int64_t *v_ARRAY_INT64 = our_int64_array; @@ -860,6 +1045,8 @@ _dbus_message_test (const char *test_data_dir) const char *s; const char *v_STRING; double v_DOUBLE; + dbus_int16_t v_INT16; + dbus_uint16_t v_UINT16; dbus_int32_t v_INT32; dbus_uint32_t v_UINT32; #ifdef DBUS_HAVE_INT64 @@ -869,6 +1056,14 @@ _dbus_message_test (const char *test_data_dir) unsigned char v_BYTE; unsigned char v2_BYTE; dbus_bool_t v_BOOLEAN; + DBusMessageIter iter, array_iter, struct_iter; +#ifdef HAVE_UNIX_FD_PASSING + int v_UNIX_FD; +#endif + char **decomposed; + DBusInitialFDs *initial_fds; + + initial_fds = _dbus_check_fdleaks_enter (); message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", "/org/freedesktop/TestPath", @@ -879,7 +1074,7 @@ _dbus_message_test (const char *test_data_dir) "TestMethod")); _dbus_assert (strcmp (dbus_message_get_path (message), "/org/freedesktop/TestPath") == 0); - _dbus_message_set_serial (message, 1234); + dbus_message_set_serial (message, 1234); /* string length including nul byte not a multiple of 4 */ if (!dbus_message_set_sender (message, "org.foo.bar1")) @@ -964,6 +1159,34 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (strcmp (dbus_message_get_member (message), "Bar") == 0); + /* Path decomposing */ + dbus_message_set_path (message, NULL); + dbus_message_get_path_decomposed (message, &decomposed); + _dbus_assert (decomposed == NULL); + dbus_free_string_array (decomposed); + + dbus_message_set_path (message, "/"); + dbus_message_get_path_decomposed (message, &decomposed); + _dbus_assert (decomposed != NULL); + _dbus_assert (decomposed[0] == NULL); + dbus_free_string_array (decomposed); + + dbus_message_set_path (message, "/a/b"); + dbus_message_get_path_decomposed (message, &decomposed); + _dbus_assert (decomposed != NULL); + _dbus_assert (strcmp (decomposed[0], "a") == 0); + _dbus_assert (strcmp (decomposed[1], "b") == 0); + _dbus_assert (decomposed[2] == NULL); + dbus_free_string_array (decomposed); + + dbus_message_set_path (message, "/spam/eggs"); + dbus_message_get_path_decomposed (message, &decomposed); + _dbus_assert (decomposed != NULL); + _dbus_assert (strcmp (decomposed[0], "spam") == 0); + _dbus_assert (strcmp (decomposed[1], "eggs") == 0); + _dbus_assert (decomposed[2] == NULL); + dbus_free_string_array (decomposed); + dbus_message_unref (message); /* Test the vararg functions */ @@ -971,9 +1194,11 @@ _dbus_message_test (const char *test_data_dir) "/org/freedesktop/TestPath", "Foo.TestInterface", "TestMethod"); - _dbus_message_set_serial (message, 1); + dbus_message_set_serial (message, 1); dbus_message_set_reply_serial (message, 5678); + v_INT16 = -0x123; + v_UINT16 = 0x123; v_INT32 = -0x12345678; v_UINT32 = 0x12300042; #ifdef DBUS_HAVE_INT64 @@ -985,8 +1210,13 @@ _dbus_message_test (const char *test_data_dir) v_BOOLEAN = TRUE; v_BYTE = 42; v2_BYTE = 24; +#ifdef HAVE_UNIX_FD_PASSING + v_UNIX_FD = 1; +#endif dbus_message_append_args (message, + DBUS_TYPE_INT16, &v_INT16, + DBUS_TYPE_UINT16, &v_UINT16, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_UINT32, &v_UINT32, #ifdef DBUS_HAVE_INT64 @@ -1014,9 +1244,14 @@ _dbus_message_test (const char *test_data_dir) _DBUS_N_ELEMENTS (our_byte_array), DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN, _DBUS_N_ELEMENTS (our_boolean_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY_STRING, + _DBUS_N_ELEMENTS (our_string_array), + DBUS_TYPE_INVALID); i = 0; + sig[i++] = DBUS_TYPE_INT16; + sig[i++] = DBUS_TYPE_UINT16; sig[i++] = DBUS_TYPE_INT32; sig[i++] = DBUS_TYPE_UINT32; #ifdef DBUS_HAVE_INT64 @@ -1044,6 +1279,17 @@ _dbus_message_test (const char *test_data_dir) sig[i++] = DBUS_TYPE_BYTE; sig[i++] = DBUS_TYPE_ARRAY; sig[i++] = DBUS_TYPE_BOOLEAN; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_STRING; + + message_without_unix_fds = dbus_message_copy(message); + _dbus_assert(message_without_unix_fds); +#ifdef HAVE_UNIX_FD_PASSING + dbus_message_append_args (message, + DBUS_TYPE_UNIX_FD, &v_UNIX_FD, + DBUS_TYPE_INVALID); + sig[i++] = DBUS_TYPE_UNIX_FD; +#endif sig[i++] = DBUS_TYPE_INVALID; _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); @@ -1092,7 +1338,7 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (copy); /* Message loader test */ - _dbus_message_lock (message); + dbus_message_lock (message); loader = _dbus_message_loader_new (); /* check ref/unref */ @@ -1121,6 +1367,20 @@ _dbus_message_test (const char *test_data_dir) _dbus_message_loader_return_buffer (loader, buffer, 1); } +#ifdef HAVE_UNIX_FD_PASSING + { + int *unix_fds; + unsigned n_unix_fds; + /* Write unix fd */ + _dbus_message_loader_get_unix_fds(loader, &unix_fds, &n_unix_fds); + _dbus_assert(n_unix_fds > 0); + _dbus_assert(message->n_unix_fds == 1); + unix_fds[0] = _dbus_dup(message->unix_fds[0], NULL); + _dbus_assert(unix_fds[0] >= 0); + _dbus_message_loader_return_unix_fds(loader, unix_fds, 1); + } +#endif + dbus_message_unref (message); /* Now pop back the message */ @@ -1137,18 +1397,107 @@ _dbus_message_test (const char *test_data_dir) if (dbus_message_get_reply_serial (message) != 5678) _dbus_assert_not_reached ("reply serial fields differ"); - verify_test_message (message); - dbus_message_unref (message); + + /* ovveride the serial, since it was reset by dbus_message_copy() */ + dbus_message_set_serial(message_without_unix_fds, 8901); + + dbus_message_lock (message_without_unix_fds); + + verify_test_message (message_without_unix_fds); + + { + /* Marshal and demarshal the message. */ + + DBusMessage *message2; + DBusError error = DBUS_ERROR_INIT; + char *marshalled = NULL; + int len = 0; + char garbage_header[DBUS_MINIMUM_HEADER_SIZE] = "xxx"; + + if (!dbus_message_marshal (message_without_unix_fds, &marshalled, &len)) + _dbus_assert_not_reached ("failed to marshal message"); + + _dbus_assert (len != 0); + _dbus_assert (marshalled != NULL); + + _dbus_assert (dbus_message_demarshal_bytes_needed (marshalled, len) == len); + message2 = dbus_message_demarshal (marshalled, len, &error); + + _dbus_assert (message2 != NULL); + _dbus_assert (!dbus_error_is_set (&error)); + verify_test_message (message2); + + dbus_message_unref (message2); + dbus_free (marshalled); + + /* Demarshal invalid message. */ + + message2 = dbus_message_demarshal ("invalid", 7, &error); + _dbus_assert (message2 == NULL); + _dbus_assert (dbus_error_is_set (&error)); + dbus_error_free (&error); + + /* Demarshal invalid (empty) message. */ + + message2 = dbus_message_demarshal ("", 0, &error); + _dbus_assert (message2 == NULL); + _dbus_assert (dbus_error_is_set (&error)); + dbus_error_free (&error); + + /* Bytes needed to demarshal empty message: 0 (more) */ + + _dbus_assert (dbus_message_demarshal_bytes_needed ("", 0) == 0); + + /* Bytes needed to demarshal invalid message: -1 (error). */ + + _dbus_assert (dbus_message_demarshal_bytes_needed (garbage_header, DBUS_MINIMUM_HEADER_SIZE) == -1); + } + + dbus_message_unref (message_without_unix_fds); _dbus_message_loader_unref (loader); check_memleaks (); + _dbus_check_fdleaks_leave (initial_fds); + initial_fds = _dbus_check_fdleaks_enter (); + + /* Check that we can abandon a container */ + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "Method"); + + dbus_message_iter_init_append (message, &iter); + + _dbus_assert (dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, + (DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING), + &array_iter)); + _dbus_assert (dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, + NULL, &struct_iter)); + + s = "peaches"; + _dbus_assert (dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, + &s)); + + /* uh-oh, error, try and unwind */ + + dbus_message_iter_abandon_container (&array_iter, &struct_iter); + dbus_message_iter_abandon_container (&array_iter, &iter); + + dbus_message_unref (message); /* Load all the sample messages from the message factory */ { DBusMessageDataIter diter; DBusMessageData mdata; + int count; + reset_validities_seen (); + + count = 0; _dbus_message_data_iter_init (&diter); while (_dbus_message_data_iter_get_and_next (&diter, @@ -1157,26 +1506,40 @@ _dbus_message_test (const char *test_data_dir) if (!dbus_internal_do_not_use_try_message_data (&mdata.data, mdata.expected_validity)) { - _dbus_warn ("expected validity %d and did not get it; generator %d sequence %d\n", - mdata.expected_validity, - diter.generator, diter.sequence); + _dbus_warn ("expected validity %d and did not get it\n", + mdata.expected_validity); _dbus_assert_not_reached ("message data failed"); } _dbus_message_data_free (&mdata); + + count += 1; } + + printf ("%d sample messages tested\n", count); + + print_validities_seen (FALSE); + print_validities_seen (TRUE); } - + check_memleaks (); - + _dbus_check_fdleaks_leave (initial_fds); + /* Now load every message in test_data_dir if we have one */ if (test_data_dir == NULL) return TRUE; - return dbus_internal_do_not_use_foreach_message_file (test_data_dir, + initial_fds = _dbus_check_fdleaks_enter (); + + if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir, (DBusForeachMessageFileFunc) dbus_internal_do_not_use_try_message_file, - NULL); + NULL)) + _dbus_assert_not_reached ("foreach_message_file test failed"); + + _dbus_check_fdleaks_leave (initial_fds); + + return TRUE; } #endif /* DBUS_BUILD_TESTS */