From 570e3df11f9c82f444fc2f5bc768b1ba66af20d3 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 9 Jun 2011 18:24:57 +0100 Subject: [PATCH 2/4] Add a test for marshalling and endian-swapping Bug: https://bugs.freedesktop.org/show_bug.cgi?id=38120 --- test/.gitignore | 1 + test/Makefile.am | 8 ++ test/marshal.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 0 deletions(-) create mode 100644 test/marshal.c diff --git a/test/.gitignore b/test/.gitignore index 77f38e5..1337de6 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -27,3 +27,4 @@ test-names test-loopback test-relay test-dbus-daemon +test-marshal diff --git a/test/Makefile.am b/test/Makefile.am index e74a8d3..afa99dc 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -80,6 +80,7 @@ installable_tests = \ test-corrupt \ test-dbus-daemon \ test-loopback \ + test-marshal \ test-relay \ $(NULL) @@ -120,6 +121,13 @@ test_dbus_daemon_LDADD = $(top_builddir)/dbus/libdbus-1.la \ $(GLIB_LIBS) \ $(DBUS_GLIB_LIBS) +test_marshal_SOURCES = marshal.c +test_marshal_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS) +test_marshal_LDFLAGS = @R_DYNAMIC_LDFLAG@ +test_marshal_LDADD = $(top_builddir)/dbus/libdbus-1.la \ + $(GLIB_LIBS) \ + $(DBUS_GLIB_LIBS) + if DBUS_ENABLE_MODULAR_TESTS TESTS += $(installable_tests) installcheck_tests += $(installable_tests) diff --git a/test/marshal.c b/test/marshal.c new file mode 100644 index 0000000..420c830 --- /dev/null +++ b/test/marshal.c @@ -0,0 +1,222 @@ +/* Simple sanity-check for D-Bus message serialization. + * + * Author: Simon McVittie + * Copyright © 2010-2011 Nokia Corporation + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include + +#include +#include + +typedef struct { + DBusError e; +} Fixture; + +static void +assert_no_error (const DBusError *e) +{ + if (G_UNLIKELY (dbus_error_is_set (e))) + g_error ("expected success but got error: %s: %s", e->name, e->message); +} + +static void +setup (Fixture *f, + gconstpointer arg G_GNUC_UNUSED) +{ + dbus_error_init (&f->e); +} + +/* this is meant to be obviously correct, not efficient! */ +static guint32 +get_uint32 (const gchar *blob, + gsize offset, + char endian) +{ + if (endian == 'l') + { + return + blob[offset] | + (blob[offset + 1] << 8) | + (blob[offset + 2] << 16) | + (blob[offset + 3] << 24); + } + else if (endian == 'B') + { + return + (blob[offset] << 24) | + (blob[offset + 1] << 16) | + (blob[offset + 2] << 8) | + blob[offset + 3]; + } + else + { + g_assert_not_reached (); + } +} + +#define BLOB_LENGTH (sizeof (le_blob) - 1) +#define OFFSET_BODY_LENGTH (4) +#define OFFSET_SERIAL (8) + +const gchar le_blob[] = + /* byte 0 */ + /* yyyyuu fixed headers */ + "l" /* little-endian */ + "\2" /* reply (which is the simplest message) */ + "\2" /* no auto-starting */ + "\1" /* D-Bus version = 1 */ + /* byte 4 */ + "\4\0\0\0" /* bytes in body = 4 */ + /* byte 8 */ + "\x78\x56\x34\x12" /* serial number = 0x12345678 */ + /* byte 12 */ + /* a(uv) variable headers start here */ + "\x0f\0\0\0" /* bytes in array of variable headers = 15 */ + /* pad to 8-byte boundary = nothing */ + /* byte 16 */ + "\5" /* in reply to: */ + "\1u\0" /* variant signature = u */ + /* pad to 4-byte boundary = nothing */ + "\x12\xef\xcd\xab" /* 0xabcdef12 */ + /* pad to 8-byte boundary = nothing */ + /* byte 24 */ + "\x08" /* signature: */ + "\1g\0" /* variant signature = g */ + "\1u\0" /* 1 byte, u, NUL (no alignment needed) */ + "\0" /* pad to 8-byte boundary for body */ + /* body; byte 32 */ + "\xef\xbe\xad\xde" /* 0xdeadbeef */ + ; + +const gchar be_blob[] = + /* byte 0 */ + /* yyyyuu fixed headers */ + "B" /* big-endian */ + "\2" /* reply (which is the simplest message) */ + "\2" /* no auto-starting */ + "\1" /* D-Bus version = 1 */ + /* byte 4 */ + "\0\0\0\4" /* bytes in body = 4 */ + /* byte 8 */ + "\x12\x34\x56\x78" /* serial number = 0x12345678 */ + /* byte 12 */ + /* a(uv) variable headers start here */ + "\0\0\0\x0f" /* bytes in array of variable headers = 15 */ + /* pad to 8-byte boundary = nothing */ + /* byte 16 */ + "\5" /* in reply to: */ + "\1u\0" /* variant signature = u */ + /* pad to 4-byte boundary = nothing */ + "\xab\xcd\xef\x12" /* 0xabcdef12 */ + /* pad to 8-byte boundary = nothing */ + /* byte 24 */ + "\x08" /* signature: */ + "\1g\0" /* variant signature = g */ + "\1u\0" /* 1 byte, u, NUL (no alignment needed) */ + "\0" /* pad to 8-byte boundary for body */ + /* body; byte 32 */ + "\xde\xad\xbe\xef" /* 0xdeadbeef */ + ; + +static void +test_endian (Fixture *f, + gconstpointer arg) +{ + const gchar *blob = arg; + const gchar *native_blob; + char *output; + DBusMessage *m; + int len; + dbus_uint32_t u; + dbus_bool_t ok; + + g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob)); + + g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4); + g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==, + 0x12345678u); + + len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob)); + /* everything in the string except the implicit "\0" at the end is part of + * the message */ + g_assert_cmpint (len, ==, BLOB_LENGTH); + + m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e); + assert_no_error (&f->e); + g_assert (m != NULL); + + g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u); + g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u); + g_assert_cmpstr (dbus_message_get_signature (m), ==, "u"); + + /* appending to the message results in it being byteswapped into compiler + * byte order */ + u = 0xdecafbadu; + ok = dbus_message_append_args (m, + DBUS_TYPE_UINT32, &u, + DBUS_TYPE_INVALID); + g_assert (ok); + + dbus_message_marshal (m, &output, &len); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + native_blob = le_blob; +#else + native_blob = be_blob; +#endif + + /* endianness, etc. are unaffected by appending a uint - but now it's in + * native byte order */ + g_assert_cmpint (output[0], ==, native_blob[0]); + g_assert_cmpint (output[1], ==, native_blob[1]); + g_assert_cmpint (output[2], ==, native_blob[2]); + g_assert_cmpint (output[3], ==, native_blob[3]); + g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8); + g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==, + 0x12345678u); + /* the second "u" in the signature replaced a padding byte, so only + * the length of the body changed */ + g_assert_cmpint (len, ==, BLOB_LENGTH + 4); +} + +static void +teardown (Fixture *f, + gconstpointer arg G_GNUC_UNUSED) +{ + dbus_error_free (&f->e); +} + +int +main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add ("/demarshal/le", Fixture, le_blob, setup, test_endian, teardown); + g_test_add ("/demarshal/be", Fixture, be_blob, setup, test_endian, teardown); + + return g_test_run (); +} -- 1.7.5.3