From 7a2c13d21be702c7b5b7288fb82a60adc5bd7378 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 30 Sep 2022 14:00:08 +0100 Subject: test: Add infrastructure to parse valid raw message blobs Signed-off-by: Simon McVittie --- test/CMakeLists.txt | 1 + test/Makefile.am | 2 + test/data/meson.build | 2 + test/data/valid-messages/minimal.message-raw | Bin 0 -> 24 bytes test/data/valid-messages/minimal.message-raw.hex | 25 ++++ test/internals/dbus-message-util.c | 4 + test/message.c | 160 +++++++++++++++++++++++ 7 files changed, 194 insertions(+) create mode 100644 test/data/valid-messages/minimal.message-raw create mode 100644 test/data/valid-messages/minimal.message-raw.hex (limited to 'test') diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cd338a07..5bd7915c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -228,6 +228,7 @@ set(TESTDIRS data/valid-config-files/session.d data/valid-config-files-system data/valid-config-files-system/system.d + data/valid-messages data/valid-service-files data/valid-service-files-system data/invalid-config-files diff --git a/test/Makefile.am b/test/Makefile.am index 659aead3..54ec3693 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -762,6 +762,8 @@ static_data = \ data/valid-config-files/standard-session-dirs.conf \ data/valid-config-files-system/many-rules.conf \ data/valid-config-files-system/system.d/test.conf \ + data/valid-messages/minimal.message-raw \ + data/valid-messages/minimal.message-raw.hex \ $(NULL) EXTRA_DIST += $(static_data) diff --git a/test/data/meson.build b/test/data/meson.build index 7ad99411..45fb6f91 100644 --- a/test/data/meson.build +++ b/test/data/meson.build @@ -110,6 +110,8 @@ data_to_install = [ 'valid-config-files/many-rules.conf', 'valid-config-files/minimal.conf', 'valid-config-files/standard-session-dirs.conf', + 'valid-messages/minimal.message-raw', + 'valid-messages/minimal.message-raw.hex', ] data_in_to_install = [ diff --git a/test/data/valid-messages/minimal.message-raw b/test/data/valid-messages/minimal.message-raw new file mode 100644 index 00000000..3b5ee188 Binary files /dev/null and b/test/data/valid-messages/minimal.message-raw differ diff --git a/test/data/valid-messages/minimal.message-raw.hex b/test/data/valid-messages/minimal.message-raw.hex new file mode 100644 index 00000000..ab0534da --- /dev/null +++ b/test/data/valid-messages/minimal.message-raw.hex @@ -0,0 +1,25 @@ +# Copyright 2022 Collabora Ltd. +# SPDX-License-Identifier: MIT +# +# To output as binary: +# sed -e 's/#.*//' test/data/valid-messages/minimal.message-raw.hex | +# xxd -p -r - test/data/valid-messages/minimal.message-raw +# +# This is a minimal valid message. + +# Offset % 0x10: +# 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f + + 6c # little-endian + 02 # method call reply + 00 # no flags + 01 # major protocol version 1 + 0000 0000 # message body is 0 bytes + 0200 0000 # serial number 2 + 0800 0000 # header is an array of 8 bytes of struct (yv) + 05 # in reply to + 01 # signature is 1 byte + 7500 # "u" \0 + 0100 0000 # in reply to serial number 1 + +#sha1 06942854add9c4346a8b1c76a2b02e2e73abe72a diff --git a/test/internals/dbus-message-util.c b/test/internals/dbus-message-util.c index df2ab8cf..25237c85 100644 --- a/test/internals/dbus-message-util.c +++ b/test/internals/dbus-message-util.c @@ -589,6 +589,10 @@ foreach_message_file (const char *test_data_dir, _dbus_string_init_const (&test_directory, test_data_dir); + if (!process_test_subdir (&test_directory, "valid-messages", + DBUS_VALID, func, user_data)) + goto failed; + if (!process_test_subdir (&test_directory, "invalid-messages", DBUS_INVALID_FOR_UNKNOWN_REASON, func, user_data)) goto failed; diff --git a/test/message.c b/test/message.c index 699302f4..58966cb8 100644 --- a/test/message.c +++ b/test/message.c @@ -28,6 +28,7 @@ #include #include +#include #include #include "dbus/dbus-internals.h" @@ -179,6 +180,152 @@ out: return !g_test_failed (); } +static void iterate_fully (DBusMessageIter *iter, + int n_elements); + +/* Iterate over @iter. If n_elements >= 0, then @iter is + * expected to yield exactly @n_elements elements. */ +static void +iterate_fully (DBusMessageIter *iter, + int n_elements) +{ + int i = 0; + + while (TRUE) + { + int arg_type = dbus_message_iter_get_arg_type (iter); + dbus_bool_t should_have_next; + dbus_bool_t had_next; + + if (arg_type == DBUS_TYPE_INVALID) + return; /* end of iteration */ + + if (dbus_type_is_container (arg_type)) + { + DBusMessageIter sub = DBUS_MESSAGE_ITER_INIT_CLOSED; + int n_contained = -1; + + switch (arg_type) + { + case DBUS_TYPE_ARRAY: + /* This is only allowed for arrays */ + n_contained = dbus_message_iter_get_element_count (iter); + g_assert_cmpint (n_contained, >=, 0); + break; + + case DBUS_TYPE_VARIANT: + n_contained = 1; + break; + + case DBUS_TYPE_STRUCT: + break; + + case DBUS_TYPE_DICT_ENTRY: + n_contained = 2; + break; + + default: + g_assert_not_reached (); + } + + dbus_message_iter_recurse (iter, &sub); + iterate_fully (&sub, n_contained); + } + else + { + DBusBasicValue value; + + dbus_message_iter_get_basic (iter, &value); + + if (arg_type == DBUS_TYPE_UNIX_FD && value.fd >= 0) + { + GError *error = NULL; + + g_close (value.fd, &error); + g_assert_no_error (error); + } + } + + should_have_next = dbus_message_iter_has_next (iter); + had_next = dbus_message_iter_next (iter); + g_assert_cmpint (had_next, ==, should_have_next); + g_assert_cmpint (had_next, ==, + (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_INVALID)); + i += 1; + } + + if (n_elements >= 0) + g_assert_cmpuint (n_elements, ==, i); +} + +/* Return TRUE if the right thing happens, but the right thing might include + * OOM. */ +static dbus_bool_t +test_valid_message_blobs (void *message_name, + dbus_bool_t have_memory) +{ + gchar *path = NULL; + gchar *contents = NULL; + gsize len = 0; + DBusMessage *m = NULL; + DBusMessageIter iter = DBUS_MESSAGE_ITER_INIT_CLOSED; + GError *error = NULL; + DBusError e = DBUS_ERROR_INIT; + dbus_bool_t ok = TRUE; + gchar *filename = NULL; + + filename = g_strdup_printf ("%s.message-raw", (const char *) message_name); + path = g_test_build_filename (G_TEST_DIST, "data", "valid-messages", + filename, NULL); + g_file_get_contents (path, &contents, &len, &error); + g_assert_no_error (error); + g_assert_cmpuint (len, <, (gsize) INT_MAX); + + m = dbus_message_demarshal (contents, (int) len, &e); + + if (m == NULL) + { + if (dbus_error_has_name (&e, DBUS_ERROR_NO_MEMORY) && !have_memory) + { + g_test_message ("Out of memory (not a problem)"); + goto out; + } + + /* TODO: Validity checking sometimes returns InvalidArgs for OOM */ + if (dbus_error_has_name (&e, DBUS_ERROR_INVALID_ARGS) && + !have_memory && + strstr (e.message, "Out of memory") != NULL) + { + g_test_message ("Out of memory (not a problem)"); + goto out; + } + + g_test_message ("Parsing %s reported unexpected error %s: %s", + path, e.name, e.message); + g_test_fail (); + ok = FALSE; + goto out; + } + + g_test_message ("Successfully parsed %s", path); + test_assert_no_error (&e); + + if (dbus_message_iter_init (m, &iter)) + g_assert_cmpint (dbus_message_iter_get_arg_type (&iter), !=, DBUS_TYPE_INVALID); + else + g_assert_cmpint (dbus_message_iter_get_arg_type (&iter), ==, DBUS_TYPE_INVALID); + + iterate_fully (&iter, -1); + +out: + dbus_clear_message (&m); + dbus_error_free (&e); + g_free (path); + g_free (contents); + g_free (filename); + return ok; +} + /* Return TRUE if the right thing happens, but the right thing might include * OOM. */ static dbus_bool_t @@ -365,6 +512,11 @@ add_oom_test (const gchar *name, g_queue_push_tail (test_cases_to_free, test_case); } +static const char *valid_messages[] = +{ + "minimal", +}; + static const char *invalid_messages[] = { "boolean-has-no-value", @@ -391,6 +543,14 @@ main (int argc, add_oom_test ("/message/fd", test_fd, NULL); add_oom_test ("/message/zero-iter", test_zero_iter, NULL); + for (i = 0; i < G_N_ELEMENTS (valid_messages); i++) + { + gchar *path = g_strdup_printf ("/message/valid/%s", valid_messages[i]); + + add_oom_test (path, test_valid_message_blobs, valid_messages[i]); + g_free (path); + } + for (i = 0; i < G_N_ELEMENTS (invalid_messages); i++) { gchar *path = g_strdup_printf ("/message/invalid/%s", invalid_messages[i]); -- cgit v1.2.1