(root)/
glib-2.79.0/
gio/
tests/
gdbus-serialization.c
       1  /* GLib testing framework examples and tests
       2   *
       3   * Copyright (C) 2008-2010 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: David Zeuthen <davidz@redhat.com>
      21   */
      22  
      23  #include <locale.h>
      24  #include <gio/gio.h>
      25  
      26  #include <string.h>
      27  #ifndef _MSC_VER
      28  #include <unistd.h>
      29  #endif
      30  #include <dbus/dbus.h>
      31  
      32  /* ---------------------------------------------------------------------------------------------------- */
      33  
      34  static void
      35  hexdump (const guchar *str, gsize len)
      36  {
      37    const guchar *data = (const guchar *) str;
      38    guint n, m;
      39  
      40    for (n = 0; n < len; n += 16)
      41      {
      42        g_printerr ("%04x: ", n);
      43  
      44        for (m = n; m < n + 16; m++)
      45          {
      46            if (m > n && (m%4) == 0)
      47              g_printerr (" ");
      48            if (m < len)
      49              g_printerr ("%02x ", data[m]);
      50            else
      51              g_printerr ("   ");
      52          }
      53  
      54        g_printerr ("   ");
      55  
      56        for (m = n; m < len && m < n + 16; m++)
      57          g_printerr ("%c", g_ascii_isprint (data[m]) ? data[m] : '.');
      58  
      59        g_printerr ("\n");
      60      }
      61  }
      62  
      63  /* ---------------------------------------------------------------------------------------------------- */
      64  
      65  static gboolean
      66  append_gv_to_dbus_iter (DBusMessageIter  *iter,
      67                          GVariant         *value,
      68                          GError          **error)
      69  {
      70    const GVariantType *type;
      71  
      72    type = g_variant_get_type (value);
      73    if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
      74      {
      75        dbus_bool_t v = g_variant_get_boolean (value);
      76        dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v);
      77      }
      78    else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
      79      {
      80        guint8 v = g_variant_get_byte (value);
      81        dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &v);
      82      }
      83    else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
      84      {
      85        gint16 v = g_variant_get_int16 (value);
      86        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &v);
      87      }
      88    else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
      89      {
      90        guint16 v = g_variant_get_uint16 (value);
      91        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &v);
      92      }
      93    else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
      94      {
      95        gint32 v = g_variant_get_int32 (value);
      96        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &v);
      97      }
      98    else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
      99      {
     100        guint32 v = g_variant_get_uint32 (value);
     101        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &v);
     102      }
     103    else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
     104      {
     105        gint64 v = g_variant_get_int64 (value);
     106        dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &v);
     107      }
     108    else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
     109      {
     110        guint64 v = g_variant_get_uint64 (value);
     111        dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &v);
     112      }
     113    else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
     114      {
     115        gdouble v = g_variant_get_double (value);
     116        dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &v);
     117      }
     118    else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
     119      {
     120        const gchar *v = g_variant_get_string (value, NULL);
     121        dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &v);
     122      }
     123    else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
     124      {
     125        const gchar *v = g_variant_get_string (value, NULL);
     126        dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &v);
     127      }
     128    else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
     129      {
     130        const gchar *v = g_variant_get_string (value, NULL);
     131        dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &v);
     132      }
     133    else if (g_variant_type_is_variant (type))
     134      {
     135        DBusMessageIter sub;
     136        GVariant *child;
     137  
     138        child = g_variant_get_child_value (value, 0);
     139        dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT,
     140                                          g_variant_get_type_string (child),
     141                                          &sub);
     142        if (!append_gv_to_dbus_iter (&sub, child, error))
     143          {
     144              g_variant_unref (child);
     145              goto fail;
     146          }
     147        dbus_message_iter_close_container (iter, &sub);
     148        g_variant_unref (child);
     149      }
     150    else if (g_variant_type_is_array (type))
     151      {
     152        DBusMessageIter dbus_iter;
     153        const gchar *type_string;
     154        GVariantIter gv_iter;
     155        GVariant *item;
     156  
     157        type_string = g_variant_get_type_string (value);
     158        type_string++; /* skip the 'a' */
     159  
     160        dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
     161                                          type_string, &dbus_iter);
     162        g_variant_iter_init (&gv_iter, value);
     163  
     164        while ((item = g_variant_iter_next_value (&gv_iter)))
     165          {
     166            if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
     167              {
     168                goto fail;
     169              }
     170          }
     171  
     172        dbus_message_iter_close_container (iter, &dbus_iter);
     173      }
     174    else if (g_variant_type_is_tuple (type))
     175      {
     176        DBusMessageIter dbus_iter;
     177        GVariantIter gv_iter;
     178        GVariant *item;
     179  
     180        dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT,
     181                                          NULL, &dbus_iter);
     182        g_variant_iter_init (&gv_iter, value);
     183  
     184        while ((item = g_variant_iter_next_value (&gv_iter)))
     185          {
     186            if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
     187              goto fail;
     188          }
     189  
     190        dbus_message_iter_close_container (iter, &dbus_iter);
     191      }
     192    else if (g_variant_type_is_dict_entry (type))
     193      {
     194        DBusMessageIter dbus_iter;
     195        GVariant *key, *val;
     196  
     197        dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY,
     198                                          NULL, &dbus_iter);
     199        key = g_variant_get_child_value (value, 0);
     200        if (!append_gv_to_dbus_iter (&dbus_iter, key, error))
     201          {
     202            g_variant_unref (key);
     203            goto fail;
     204          }
     205        g_variant_unref (key);
     206  
     207        val = g_variant_get_child_value (value, 1);
     208        if (!append_gv_to_dbus_iter (&dbus_iter, val, error))
     209          {
     210            g_variant_unref (val);
     211            goto fail;
     212          }
     213        g_variant_unref (val);
     214  
     215        dbus_message_iter_close_container (iter, &dbus_iter);
     216      }
     217    else
     218      {
     219        g_set_error (error,
     220                     G_IO_ERROR,
     221                     G_IO_ERROR_INVALID_ARGUMENT,
     222                     "Error serializing GVariant with type-string '%s' to a D-Bus message",
     223                     g_variant_get_type_string (value));
     224        goto fail;
     225      }
     226  
     227    return TRUE;
     228  
     229   fail:
     230    return FALSE;
     231  }
     232  
     233  static gboolean
     234  append_gv_to_dbus_message (DBusMessage  *message,
     235                             GVariant     *value,
     236                             GError      **error)
     237  {
     238    gboolean ret;
     239    guint n;
     240  
     241    ret = FALSE;
     242  
     243    if (value != NULL)
     244      {
     245        DBusMessageIter iter;
     246        GVariantIter gv_iter;
     247        GVariant *item;
     248  
     249        dbus_message_iter_init_append (message, &iter);
     250  
     251        g_variant_iter_init (&gv_iter, value);
     252        n = 0;
     253        while ((item = g_variant_iter_next_value (&gv_iter)))
     254          {
     255            if (!append_gv_to_dbus_iter (&iter, item, error))
     256              {
     257                g_prefix_error (error,
     258                                "Error encoding in-arg %d: ",
     259                                n);
     260                goto out;
     261              }
     262            n++;
     263          }
     264      }
     265  
     266    ret = TRUE;
     267  
     268   out:
     269    return ret;
     270  }
     271  
     272  static void
     273  print_gv_dbus_message (GVariant *value)
     274  {
     275    DBusMessage *message;
     276    char *blob;
     277    int blob_len;
     278    GError *error;
     279  
     280    message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
     281    dbus_message_set_serial (message, 0x41);
     282    dbus_message_set_path (message, "/foo/bar");
     283    dbus_message_set_member (message, "Member");
     284  
     285    error = NULL;
     286    if (!append_gv_to_dbus_message (message, value, &error))
     287      {
     288        g_printerr ("Error printing GVariant as DBusMessage: %s", error->message);
     289        g_error_free (error);
     290        goto out;
     291      }
     292  
     293    dbus_message_marshal (message, &blob, &blob_len);
     294    g_printerr ("\n");
     295    hexdump ((guchar *) blob, blob_len);
     296   out:
     297    dbus_message_unref (message);
     298  }
     299  
     300  /* ---------------------------------------------------------------------------------------------------- */
     301  
     302  static void
     303  dbus_1_message_append (GString *s,
     304                         guint indent,
     305                         DBusMessageIter *iter)
     306  {
     307    gint arg_type;
     308    DBusMessageIter sub;
     309  
     310    g_string_append_printf (s, "%*s", indent, "");
     311  
     312    arg_type = dbus_message_iter_get_arg_type (iter);
     313    switch (arg_type)
     314      {
     315       case DBUS_TYPE_BOOLEAN:
     316        {
     317          dbus_bool_t value;
     318          dbus_message_iter_get_basic (iter, &value);
     319          g_string_append_printf (s, "bool: %s\n", value ? "true" : "false");
     320          break;
     321        }
     322  
     323       case DBUS_TYPE_BYTE:
     324        {
     325          guchar value;
     326          dbus_message_iter_get_basic (iter, &value);
     327          g_string_append_printf (s, "byte: 0x%02x\n", (guint) value);
     328          break;
     329        }
     330  
     331       case DBUS_TYPE_INT16:
     332        {
     333          gint16 value;
     334          dbus_message_iter_get_basic (iter, &value);
     335          g_string_append_printf (s, "int16: %" G_GINT16_FORMAT "\n", value);
     336          break;
     337        }
     338  
     339       case DBUS_TYPE_UINT16:
     340        {
     341          guint16 value;
     342          dbus_message_iter_get_basic (iter, &value);
     343          g_string_append_printf (s, "uint16: %" G_GUINT16_FORMAT "\n", value);
     344          break;
     345        }
     346  
     347       case DBUS_TYPE_INT32:
     348        {
     349          gint32 value;
     350          dbus_message_iter_get_basic (iter, &value);
     351          g_string_append_printf (s, "int32: %" G_GINT32_FORMAT "\n", value);
     352          break;
     353        }
     354  
     355       case DBUS_TYPE_UINT32:
     356        {
     357          guint32 value;
     358          dbus_message_iter_get_basic (iter, &value);
     359          g_string_append_printf (s, "uint32: %" G_GUINT32_FORMAT "\n", value);
     360          break;
     361        }
     362  
     363       case DBUS_TYPE_INT64:
     364        {
     365          gint64 value;
     366          dbus_message_iter_get_basic (iter, &value);
     367          g_string_append_printf (s, "int64: %" G_GINT64_FORMAT "\n", value);
     368          break;
     369        }
     370  
     371       case DBUS_TYPE_UINT64:
     372        {
     373          guint64 value;
     374          dbus_message_iter_get_basic (iter, &value);
     375          g_string_append_printf (s, "uint64: %" G_GUINT64_FORMAT "\n", value);
     376          break;
     377        }
     378  
     379       case DBUS_TYPE_DOUBLE:
     380        {
     381          gdouble value;
     382          dbus_message_iter_get_basic (iter, &value);
     383          g_string_append_printf (s, "double: %f\n", value);
     384          break;
     385        }
     386  
     387       case DBUS_TYPE_STRING:
     388        {
     389          const gchar *value;
     390          dbus_message_iter_get_basic (iter, &value);
     391          g_string_append_printf (s, "string: '%s'\n", value);
     392          break;
     393        }
     394  
     395       case DBUS_TYPE_OBJECT_PATH:
     396        {
     397          const gchar *value;
     398          dbus_message_iter_get_basic (iter, &value);
     399          g_string_append_printf (s, "object_path: '%s'\n", value);
     400          break;
     401        }
     402  
     403       case DBUS_TYPE_SIGNATURE:
     404        {
     405          const gchar *value;
     406          dbus_message_iter_get_basic (iter, &value);
     407          g_string_append_printf (s, "signature: '%s'\n", value);
     408          break;
     409        }
     410  
     411  #ifdef DBUS_TYPE_UNIX_FD
     412      case DBUS_TYPE_UNIX_FD:
     413        {
     414          /* unfortunately there's currently no way to get just the
     415           * protocol value, since dbus_message_iter_get_basic() wants
     416           * to be 'helpful' and dup the fd for the user...
     417           */
     418          g_string_append (s, "unix-fd: (not extracted)\n");
     419          break;
     420        }
     421  #endif
     422  
     423       case DBUS_TYPE_VARIANT:
     424         g_string_append_printf (s, "variant:\n");
     425         dbus_message_iter_recurse (iter, &sub);
     426         while (dbus_message_iter_get_arg_type (&sub))
     427           {
     428             dbus_1_message_append (s, indent + 2, &sub);
     429             dbus_message_iter_next (&sub);
     430           }
     431         break;
     432  
     433       case DBUS_TYPE_ARRAY:
     434         g_string_append_printf (s, "array:\n");
     435         dbus_message_iter_recurse (iter, &sub);
     436         while (dbus_message_iter_get_arg_type (&sub))
     437           {
     438             dbus_1_message_append (s, indent + 2, &sub);
     439             dbus_message_iter_next (&sub);
     440           }
     441         break;
     442  
     443       case DBUS_TYPE_STRUCT:
     444         g_string_append_printf (s, "struct:\n");
     445         dbus_message_iter_recurse (iter, &sub);
     446         while (dbus_message_iter_get_arg_type (&sub))
     447           {
     448             dbus_1_message_append (s, indent + 2, &sub);
     449             dbus_message_iter_next (&sub);
     450           }
     451         break;
     452  
     453       case DBUS_TYPE_DICT_ENTRY:
     454         g_string_append_printf (s, "dict_entry:\n");
     455         dbus_message_iter_recurse (iter, &sub);
     456         while (dbus_message_iter_get_arg_type (&sub))
     457           {
     458             dbus_1_message_append (s, indent + 2, &sub);
     459             dbus_message_iter_next (&sub);
     460           }
     461         break;
     462  
     463       default:
     464         g_printerr ("Error serializing D-Bus message to GVariant. Unsupported arg type '%c' (%d)",
     465                     arg_type,
     466                     arg_type);
     467         g_assert_not_reached ();
     468         break;
     469      }
     470  }
     471  
     472  static gchar *
     473  dbus_1_message_print (DBusMessage *message)
     474  {
     475    GString *s;
     476    guint n;
     477    DBusMessageIter iter;
     478  
     479    s = g_string_new (NULL);
     480    n = 0;
     481    dbus_message_iter_init (message, &iter);
     482    while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
     483      {
     484        g_string_append_printf (s, "value %d: ", n);
     485        dbus_1_message_append (s, 2, &iter);
     486        dbus_message_iter_next (&iter);
     487        n++;
     488      }
     489  
     490    return g_string_free (s, FALSE);
     491  }
     492  
     493  /* ---------------------------------------------------------------------------------------------------- */
     494  
     495  static gchar *
     496  get_body_signature (GVariant *value)
     497  {
     498    const gchar *s;
     499    gsize len;
     500    gchar *ret;
     501  
     502    if (value == NULL)
     503      {
     504        ret = g_strdup ("");
     505        goto out;
     506      }
     507  
     508    s = g_variant_get_type_string (value);
     509    len = strlen (s);
     510    g_assert (len >= 2);
     511  
     512    ret = g_strndup (s + 1, len - 2);
     513  
     514   out:
     515    return ret;
     516  }
     517  
     518  /* If @value is floating, this assumes ownership. */
     519  static gchar *
     520  get_and_check_serialization (GVariant *value)
     521  {
     522    guchar *blob;
     523    gsize blob_size;
     524    DBusMessage *dbus_1_message;
     525    GDBusMessage *message;
     526    GDBusMessage *recovered_message;
     527    GError *error;
     528    DBusError dbus_error;
     529    gchar *last_serialization = NULL;
     530    gchar *s = NULL;
     531    guint n;
     532  
     533    message = g_dbus_message_new ();
     534    g_dbus_message_set_body (message, value);
     535    g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
     536    g_dbus_message_set_serial (message, 0x41);
     537    s = get_body_signature (value);
     538    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, g_variant_new_object_path ("/foo/bar"));
     539    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, g_variant_new_string ("Member"));
     540    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_signature (s));
     541    g_free (s);
     542  
     543    /* First check that the serialization to the D-Bus wire format is correct - do this for both byte orders */
     544    for (n = 0; n < 2; n++)
     545      {
     546        GDBusMessageByteOrder byte_order;
     547        switch (n)
     548          {
     549          case 0:
     550            byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
     551            break;
     552          case 1:
     553            byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
     554            break;
     555          case 2:
     556            g_assert_not_reached ();
     557            break;
     558          }
     559        g_dbus_message_set_byte_order (message, byte_order);
     560  
     561        error = NULL;
     562        blob = g_dbus_message_to_blob (message,
     563                                       &blob_size,
     564                                       G_DBUS_CAPABILITY_FLAGS_NONE,
     565                                       &error);
     566        g_assert_no_error (error);
     567        g_assert (blob != NULL);
     568  
     569        switch (byte_order)
     570          {
     571          case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN:
     572            g_assert_cmpint (blob[0], ==, 'B');
     573            break;
     574          case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN:
     575            g_assert_cmpint (blob[0], ==, 'l');
     576            break;
     577          }
     578  
     579        dbus_error_init (&dbus_error);
     580        dbus_1_message = dbus_message_demarshal ((char *) blob, blob_size, &dbus_error);
     581        if (dbus_error_is_set (&dbus_error))
     582          {
     583            g_printerr ("Error calling dbus_message_demarshal() on this blob: %s: %s\n",
     584                        dbus_error.name,
     585                        dbus_error.message);
     586            hexdump (blob, blob_size);
     587            dbus_error_free (&dbus_error);
     588  
     589            s = g_variant_print (value, TRUE);
     590            g_printerr ("\nThe blob was generated from the following GVariant value:\n%s\n\n", s);
     591            g_free (s);
     592  
     593            g_printerr ("If the blob was encoded using DBusMessageIter, the payload would have been:\n");
     594            print_gv_dbus_message (value);
     595  
     596            g_assert_not_reached ();
     597          }
     598  
     599        s = dbus_1_message_print (dbus_1_message);
     600        dbus_message_unref (dbus_1_message);
     601  
     602        /* Then serialize back and check that the body is identical */
     603  
     604        error = NULL;
     605        recovered_message = g_dbus_message_new_from_blob (blob,
     606                                                          blob_size,
     607                                                          G_DBUS_CAPABILITY_FLAGS_NONE,
     608                                                          &error);
     609        g_assert_no_error (error);
     610        g_assert (recovered_message != NULL);
     611  
     612        if (value == NULL)
     613          {
     614            g_assert (g_dbus_message_get_body (recovered_message) == NULL);
     615          }
     616        else
     617          {
     618            g_assert (g_dbus_message_get_body (recovered_message) != NULL);
     619            g_assert_cmpvariant (g_dbus_message_get_body (recovered_message), value);
     620          }
     621        g_object_unref (recovered_message);
     622        g_free (blob);
     623  
     624        if (last_serialization != NULL)
     625          {
     626            g_assert_cmpstr (last_serialization, ==, s);
     627            g_free (last_serialization);
     628          }
     629  
     630        last_serialization = g_steal_pointer (&s);
     631      }
     632  
     633    g_object_unref (message);
     634  
     635    return g_steal_pointer (&last_serialization);
     636  }
     637  
     638  /* If @value is floating, this assumes ownership. */
     639  static void
     640  check_serialization (GVariant *value,
     641                       const gchar *expected_dbus_1_output)
     642  {
     643    gchar *s = get_and_check_serialization (value);
     644    g_assert_cmpstr (s, ==, expected_dbus_1_output);
     645    g_free (s);
     646  }
     647  
     648  static void
     649  test_message_serialize_basic (void)
     650  {
     651    check_serialization (NULL, "");
     652  
     653    check_serialization (g_variant_new ("(sogybnqiuxtd)",
     654                                        "this is a string",
     655                                        "/this/is/a/path",
     656                                        "sad",
     657                                        42,
     658                                        TRUE,
     659                                        -42,
     660                                        60000,
     661                                        -44,
     662                                        100000,
     663                                        -(G_GUINT64_CONSTANT(2)<<34),
     664                                        G_GUINT64_CONSTANT(0xffffffffffffffff),
     665                                        42.5),
     666                         "value 0:   string: 'this is a string'\n"
     667                         "value 1:   object_path: '/this/is/a/path'\n"
     668                         "value 2:   signature: 'sad'\n"
     669                         "value 3:   byte: 0x2a\n"
     670                         "value 4:   bool: true\n"
     671                         "value 5:   int16: -42\n"
     672                         "value 6:   uint16: 60000\n"
     673                         "value 7:   int32: -44\n"
     674                         "value 8:   uint32: 100000\n"
     675                         "value 9:   int64: -34359738368\n"
     676                         "value 10:   uint64: 18446744073709551615\n"
     677                         "value 11:   double: 42.500000\n");
     678  }
     679  
     680  /* ---------------------------------------------------------------------------------------------------- */
     681  
     682  static void
     683  test_message_serialize_complex (void)
     684  {
     685    GError *error;
     686    GVariant *value;
     687    guint i;
     688    gchar *serialization = NULL;
     689  
     690    error = NULL;
     691  
     692    value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
     693                             "([1, 2, 3], {'one': 'white', 'two': 'black'})",
     694                             NULL, NULL, &error);
     695    g_assert_no_error (error);
     696    g_assert (value != NULL);
     697    check_serialization (value,
     698                         "value 0:   array:\n"
     699                         "    int32: 1\n"
     700                         "    int32: 2\n"
     701                         "    int32: 3\n"
     702                         "value 1:   array:\n"
     703                         "    dict_entry:\n"
     704                         "      string: 'one'\n"
     705                         "      string: 'white'\n"
     706                         "    dict_entry:\n"
     707                         "      string: 'two'\n"
     708                         "      string: 'black'\n");
     709    g_variant_unref (value);
     710  
     711    value = g_variant_parse (G_VARIANT_TYPE ("(sa{sv}as)"),
     712                             "('01234567890123456', {}, ['Something'])",
     713                             NULL, NULL, &error);
     714    g_assert_no_error (error);
     715    g_assert (value != NULL);
     716    check_serialization (value,
     717                         "value 0:   string: '01234567890123456'\n"
     718                         "value 1:   array:\n"
     719                         "value 2:   array:\n"
     720                         "    string: 'Something'\n");
     721    g_variant_unref (value);
     722  
     723    /* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
     724    check_serialization (g_variant_new_parsed ("(@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>})"),
     725                         "value 0:   array:\n"
     726                         "value 1:   array:\n"
     727                         "    dict_entry:\n"
     728                         "      string: 'cwd'\n"
     729                         "      variant:\n"
     730                         "        string: '/home/davidz/Hacking/glib/gio/tests'\n");
     731  
     732  #ifdef DBUS_TYPE_UNIX_FD
     733    value = g_variant_parse (G_VARIANT_TYPE ("(hah)"),
     734                             "(42, [43, 44])",
     735                             NULL, NULL, &error);
     736    g_assert_no_error (error);
     737    g_assert (value != NULL);
     738    /* about (not extracted), see comment in DBUS_TYPE_UNIX_FD case in
     739     * dbus_1_message_append() above.
     740     */
     741    check_serialization (value,
     742                         "value 0:   unix-fd: (not extracted)\n"
     743                         "value 1:   array:\n"
     744                         "    unix-fd: (not extracted)\n"
     745                         "    unix-fd: (not extracted)\n");
     746    g_variant_unref (value);
     747  #endif
     748  
     749    /* Deep nesting of variants (just below the recursion limit). */
     750    value = g_variant_new_string ("buried");
     751    for (i = 0; i < 64; i++)
     752      value = g_variant_new_variant (value);
     753    value = g_variant_new_tuple (&value, 1);
     754  
     755    serialization = get_and_check_serialization (value);
     756    g_assert_nonnull (serialization);
     757    g_assert_true (g_str_has_prefix (serialization,
     758                                     "value 0:   variant:\n"
     759                                     "    variant:\n"
     760                                     "      variant:\n"));
     761    g_free (serialization);
     762  
     763    /* Deep nesting of arrays and structs (just below the recursion limit).
     764     * See https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature */
     765    value = g_variant_new_string ("hello");
     766    for (i = 0; i < 32; i++)
     767      value = g_variant_new_tuple (&value, 1);
     768    for (i = 0; i < 32; i++)
     769      value = g_variant_new_array (NULL, &value, 1);
     770    value = g_variant_new_tuple (&value, 1);
     771  
     772    serialization = get_and_check_serialization (value);
     773    g_assert_nonnull (serialization);
     774    g_assert_true (g_str_has_prefix (serialization,
     775                                     "value 0:   array:\n"
     776                                     "    array:\n"
     777                                     "      array:\n"));
     778    g_free (serialization);
     779  }
     780  
     781  
     782  /* ---------------------------------------------------------------------------------------------------- */
     783  
     784  static void
     785  replace (char       *blob,
     786           gsize       len,
     787  	 const char *before,
     788  	 const char *after)
     789  {
     790    gsize i;
     791    gsize slen = strlen (before) + 1;
     792  
     793    g_assert_cmpuint (strlen (before), ==, strlen (after));
     794    g_assert_cmpuint (len, >=, slen);
     795  
     796    for (i = 0; i < (len - slen + 1); i++)
     797      {
     798        if (memcmp (blob + i, before, slen) == 0)
     799          memcpy (blob + i, after, slen);
     800      }
     801  }
     802  
     803  static void
     804  test_message_serialize_invalid (void)
     805  {
     806    guint n;
     807  
     808    /* Other things we could check (note that GDBus _does_ check for all
     809     * these things - we just don't have test-suit coverage for it)
     810     *
     811     *  - array exceeding 64 MiB (2^26 bytes) - unfortunately libdbus-1 checks
     812     *    this, e.g.
     813     *
     814     *      process 19620: arguments to dbus_message_iter_append_fixed_array() were incorrect,
     815     *      assertion "n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type)"
     816     *      failed in file dbus-message.c line 2344.
     817     *      This is normally a bug in some application using the D-Bus library.
     818     *      D-Bus not built with -rdynamic so unable to print a backtrace
     819     *      Aborted (core dumped)
     820     *
     821     *  - message exceeding 128 MiB (2^27 bytes)
     822     *
     823     *  - endianness, message type, flags, protocol version
     824     */
     825  
     826    for (n = 0; n < 3; n++)
     827      {
     828        GDBusMessage *message;
     829        GError *error;
     830        DBusMessage *dbus_message;
     831        char *blob;
     832        int blob_len;
     833        /* these are in pairs with matching length */
     834        const gchar *valid_utf8_str = "this is valid...";
     835        const gchar *invalid_utf8_str = "this is invalid\xff";
     836        const gchar *valid_signature = "a{sv}a{sv}a{sv}aiai";
     837        const gchar *invalid_signature = "not valid signature";
     838        const gchar *valid_object_path = "/this/is/a/valid/dbus/object/path";
     839        const gchar *invalid_object_path = "/this/is/not a valid object path!";
     840  
     841        dbus_message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
     842        dbus_message_set_serial (dbus_message, 0x41);
     843        dbus_message_set_path (dbus_message, "/foo/bar");
     844        dbus_message_set_member (dbus_message, "Member");
     845        switch (n)
     846          {
     847          case 0:
     848            /* invalid UTF-8 */
     849            dbus_message_append_args (dbus_message,
     850                                      DBUS_TYPE_STRING, &valid_utf8_str,
     851                                      DBUS_TYPE_INVALID);
     852            break;
     853  
     854          case 1:
     855            /* invalid object path */
     856            dbus_message_append_args (dbus_message,
     857                                      DBUS_TYPE_OBJECT_PATH, &valid_object_path,
     858                                      DBUS_TYPE_INVALID);
     859            break;
     860  
     861          case 2:
     862            /* invalid signature */
     863            dbus_message_append_args (dbus_message,
     864                                      DBUS_TYPE_SIGNATURE, &valid_signature,
     865                                      DBUS_TYPE_INVALID);
     866            break;
     867  
     868          default:
     869            g_assert_not_reached ();
     870            break;
     871          }
     872        dbus_message_marshal (dbus_message, &blob, &blob_len);
     873        /* hack up the message to be invalid by replacing each valid string
     874         * with its invalid counterpart */
     875        replace (blob, blob_len, valid_utf8_str, invalid_utf8_str);
     876        replace (blob, blob_len, valid_object_path, invalid_object_path);
     877        replace (blob, blob_len, valid_signature, invalid_signature);
     878  
     879        error = NULL;
     880        message = g_dbus_message_new_from_blob ((guchar *) blob,
     881                                                blob_len,
     882                                                G_DBUS_CAPABILITY_FLAGS_NONE,
     883                                                &error);
     884        g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     885        g_error_free (error);
     886        g_assert (message == NULL);
     887  
     888        dbus_free (blob);
     889        dbus_message_unref (dbus_message);
     890      }
     891  
     892  }
     893  
     894  /* ---------------------------------------------------------------------------------------------------- */
     895  
     896  static void
     897  test_message_serialize_header_checks (void)
     898  {
     899    GDBusMessage *message;
     900    GDBusMessage *reply;
     901    GError *error = NULL;
     902    guchar *blob;
     903    gsize blob_size;
     904  
     905    /*
     906     * check we can't serialize messages with INVALID type
     907     */
     908    message = g_dbus_message_new ();
     909    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     910    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     911    g_assert_cmpstr (error->message, ==, "Cannot serialize message: type is INVALID");
     912    g_clear_error (&error);
     913    g_assert_null (blob);
     914    g_object_unref (message);
     915  
     916    /*
     917     * check that we can't serialize messages with SIGNATURE set to a non-signature-typed value
     918     */
     919    message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
     920    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_boolean (FALSE));
     921    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     922  
     923    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     924    g_assert_cmpstr (error->message, ==, "Signature header found but is not of type signature");
     925    g_assert_null (blob);
     926  
     927    g_clear_error (&error);
     928    g_clear_object (&message);
     929  
     930    /*
     931     * check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
     932     */
     933    message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
     934    /* ----- */
     935    /* interface NULL => error */
     936    g_dbus_message_set_interface (message, NULL);
     937    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     938    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     939    g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid");
     940    g_clear_error (&error);
     941    g_assert_null (blob);
     942    /* interface reserved value => error */
     943    g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
     944    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     945    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     946    g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
     947    g_clear_error (&error);
     948    g_assert_null (blob);
     949    /* reset interface */
     950    g_dbus_message_set_interface (message, "The.Interface");
     951    /* ----- */
     952    /* path NULL => error */
     953    g_dbus_message_set_path (message, NULL);
     954    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     955    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     956    g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid");
     957    g_clear_error (&error);
     958    g_assert_null (blob);
     959    /* path reserved value => error */
     960    g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
     961    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     962    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     963    g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local");
     964    g_clear_error (&error);
     965    g_assert_null (blob);
     966    /* reset path */
     967    g_dbus_message_set_path (message, "/the/path");
     968    /* ----- */
     969    /* member NULL => error */
     970    g_dbus_message_set_member (message, NULL);
     971    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     972    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     973    g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid");
     974    g_clear_error (&error);
     975    g_assert_null (blob);
     976    /* reset member */
     977    g_dbus_message_set_member (message, "TheMember");
     978    /* ----- */
     979    /* done */
     980    g_object_unref (message);
     981  
     982    /*
     983     * check that we can't serialize method call messages with PATH or MEMBER unset
     984     */
     985    message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
     986    /* ----- */
     987    /* path NULL => error */
     988    g_dbus_message_set_path (message, NULL);
     989    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
     990    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
     991    g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing or invalid");
     992    g_clear_error (&error);
     993    g_assert_null (blob);
     994    /* reset path */
     995    g_dbus_message_set_path (message, "/the/path");
     996    /* ----- */
     997    /* member NULL => error */
     998    g_dbus_message_set_member (message, NULL);
     999    blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1000    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1001    g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing or invalid");
    1002    g_clear_error (&error);
    1003    g_assert_null (blob);
    1004    /* reset member */
    1005    g_dbus_message_set_member (message, "TheMember");
    1006    /* ----- */
    1007    /* done */
    1008    g_object_unref (message);
    1009  
    1010    /*
    1011     * check that we can't serialize method reply messages with REPLY_SERIAL unset
    1012     */
    1013    message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
    1014    g_dbus_message_set_serial (message, 42);
    1015    /* method reply */
    1016    reply = g_dbus_message_new_method_reply (message);
    1017    g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
    1018    g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
    1019    blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1020    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1021    g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid");
    1022    g_clear_error (&error);
    1023    g_assert_null (blob);
    1024    g_object_unref (reply);
    1025    /* method error - first nuke ERROR_NAME, then REPLY_SERIAL */
    1026    reply = g_dbus_message_new_method_error (message, "Some.Error.Name", "the message");
    1027    g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
    1028    /* nuke ERROR_NAME */
    1029    g_dbus_message_set_error_name (reply, NULL);
    1030    blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1031    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1032    g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid");
    1033    g_clear_error (&error);
    1034    g_assert_null (blob);
    1035    /* reset ERROR_NAME */
    1036    g_dbus_message_set_error_name (reply, "Some.Error.Name");
    1037    /* nuke REPLY_SERIAL */
    1038    g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
    1039    blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1040    g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1041    g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid");
    1042    g_clear_error (&error);
    1043    g_assert_null (blob);
    1044    g_object_unref (reply);
    1045    g_object_unref (message);
    1046  }
    1047  
    1048  /* ---------------------------------------------------------------------------------------------------- */
    1049  
    1050  static void
    1051  test_message_parse_empty_arrays_of_arrays (void)
    1052  {
    1053    GVariant *body;
    1054    GError *error = NULL;
    1055  
    1056    g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=673612");
    1057    /* These three-element array of empty arrays were previously read back as a
    1058     * two-element array of empty arrays, due to sometimes erroneously skipping
    1059     * four bytes to align for the eight-byte-aligned grandchild types (x and
    1060     * dict_entry).
    1061     */
    1062    body = g_variant_parse (G_VARIANT_TYPE ("(aaax)"),
    1063        "([@aax [], [], []],)", NULL, NULL, &error);
    1064    g_assert_no_error (error);
    1065    check_serialization (body,
    1066        "value 0:   array:\n"
    1067        "    array:\n"
    1068        "    array:\n"
    1069        "    array:\n");
    1070    g_variant_unref (body);
    1071  
    1072    body = g_variant_parse (G_VARIANT_TYPE ("(aaa{uu})"),
    1073        "([@aa{uu} [], [], []],)", NULL, NULL, &error);
    1074    g_assert_no_error (error);
    1075    check_serialization (body,
    1076        "value 0:   array:\n"
    1077        "    array:\n"
    1078        "    array:\n"
    1079        "    array:\n");
    1080    g_variant_unref (body);
    1081  
    1082    /* Due to the same bug, g_dbus_message_new_from_blob() would fail for this
    1083     * message because it would try to read past the end of the string. Hence,
    1084     * sending this to an application would make it fall off the bus. */
    1085    body = g_variant_parse (G_VARIANT_TYPE ("(a(aa{sv}as))"),
    1086        "([ ([], []),"
    1087        "   ([], []),"
    1088        "   ([], [])],)", NULL, NULL, &error);
    1089    g_assert_no_error (error);
    1090    check_serialization (body,
    1091        "value 0:   array:\n"
    1092        "    struct:\n"
    1093        "      array:\n"
    1094        "      array:\n"
    1095        "    struct:\n"
    1096        "      array:\n"
    1097        "      array:\n"
    1098        "    struct:\n"
    1099        "      array:\n"
    1100        "      array:\n");
    1101    g_variant_unref (body);
    1102  }
    1103  
    1104  /* ---------------------------------------------------------------------------------------------------- */
    1105  
    1106  static void
    1107  test_message_serialize_double_array (void)
    1108  {
    1109    GVariantBuilder builder;
    1110    GVariant *body;
    1111  
    1112    g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=732754");
    1113  
    1114    g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
    1115    g_variant_builder_add (&builder, "d", (gdouble)0.0);
    1116    g_variant_builder_add (&builder, "d", (gdouble)8.0);
    1117    g_variant_builder_add (&builder, "d", (gdouble)22.0);
    1118    g_variant_builder_add (&builder, "d", (gdouble)0.0);
    1119    body = g_variant_new ("(@ad)", g_variant_builder_end (&builder));
    1120    check_serialization (body,
    1121        "value 0:   array:\n"
    1122        "    double: 0.000000\n"
    1123        "    double: 8.000000\n"
    1124        "    double: 22.000000\n"
    1125        "    double: 0.000000\n");
    1126  }
    1127  
    1128  /* ---------------------------------------------------------------------------------------------------- */
    1129  
    1130  /* Test that an invalid header in a D-Bus message (specifically, with a type
    1131   * which doesn’t match what’s expected for the given header) is gracefully
    1132   * handled with an error rather than a crash. */
    1133  static void
    1134  test_message_parse_non_signature_header (void)
    1135  {
    1136    const guint8 data[] = {
    1137      'l',  /* little-endian byte order */
    1138      0x02,  /* message type (method return) */
    1139      0x00,  /* message flags (none) */
    1140      0x01,  /* major protocol version */
    1141      0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1142      0x00, 0x00, 0x00, 0xbc,  /* message serial */
    1143      /* a{yv} of header fields:
    1144       * (things start to be invalid below here) */
    1145      0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1146        0x08, /* array key (SIGNATURE) */
    1147        /* Variant array value: */
    1148        0x04, /* signature length */
    1149        'd', 0x00, 0x00, 'F',  /* signature (invalid) */
    1150        0x00,  /* nul terminator */
    1151        /* (Variant array value payload missing) */
    1152        /* alignment padding before the next header array element, as structs must
    1153         * be 8-aligned: */
    1154        0x00,
    1155        0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
    1156        /* Variant array value: */
    1157        0x01,  /* signature length */
    1158        'u',  /* one complete type */
    1159        0x00,  /* nul terminator */
    1160        /* (Variant array value payload) */
    1161        0x00, 0x01, 0x02, 0x03,
    1162      /* (message body is zero-length) */
    1163    };
    1164    gsize size = sizeof (data);
    1165    GDBusMessage *message = NULL;
    1166    GError *local_error = NULL;
    1167  
    1168    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1169                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1170                                            &local_error);
    1171    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1172    g_assert_null (message);
    1173  
    1174    g_clear_error (&local_error);
    1175  }
    1176  
    1177  /* ---------------------------------------------------------------------------------------------------- */
    1178  
    1179  /* Test that an invalid header in a D-Bus message (specifically, containing a
    1180   * variant with an empty type signature) is gracefully handled with an error
    1181   * rather than a crash. */
    1182  static void
    1183  test_message_parse_empty_signature_header (void)
    1184  {
    1185    const guint8 data[] = {
    1186      'l',  /* little-endian byte order */
    1187      0x02,  /* message type (method return) */
    1188      0x00,  /* message flags (none) */
    1189      0x01,  /* major protocol version */
    1190      0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1191      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1192      /* a{yv} of header fields:
    1193       * (things start to be invalid below here) */
    1194      0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1195        0x20, /* array key (this is not currently a valid header field) */
    1196        /* Variant array value: */
    1197        0x00, /* signature length */
    1198        0x00,  /* nul terminator */
    1199        /* (Variant array value payload missing) */
    1200        /* alignment padding before the next header array element, as structs must
    1201         * be 8-aligned: */
    1202        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1203        0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
    1204        /* Variant array value: */
    1205        0x01,  /* signature length */
    1206        'u',  /* one complete type */
    1207        0x00,  /* nul terminator */
    1208        /* (Variant array value payload) */
    1209        0x00, 0x01, 0x02, 0x03,
    1210      /* (message body is zero-length) */
    1211    };
    1212    gsize size = sizeof (data);
    1213    GDBusMessage *message = NULL;
    1214    GError *local_error = NULL;
    1215  
    1216    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1217                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1218                                            &local_error);
    1219    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1220    g_assert_null (message);
    1221  
    1222    g_clear_error (&local_error);
    1223  }
    1224  
    1225  /* ---------------------------------------------------------------------------------------------------- */
    1226  
    1227  /* Test that an invalid header in a D-Bus message (specifically, containing a
    1228   * variant with a type signature containing multiple complete types) is
    1229   * gracefully handled with an error rather than a crash. */
    1230  static void
    1231  test_message_parse_multiple_signature_header (void)
    1232  {
    1233    const guint8 data[] = {
    1234      'l',  /* little-endian byte order */
    1235      0x02,  /* message type (method return) */
    1236      0x00,  /* message flags (none) */
    1237      0x01,  /* major protocol version */
    1238      0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1239      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1240      /* a{yv} of header fields:
    1241       * (things start to be invalid below here) */
    1242      0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1243        0x20, /* array key (this is not currently a valid header field) */
    1244        /* Variant array value: */
    1245        0x02, /* signature length */
    1246        'b', 'b',  /* two complete types */
    1247        0x00,  /* nul terminator */
    1248        /* (Variant array value payload missing) */
    1249        /* alignment padding before the next header array element, as structs must
    1250         * be 8-aligned: */
    1251        0x00, 0x00, 0x00,
    1252        0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
    1253        /* Variant array value: */
    1254        0x01,  /* signature length */
    1255        'u',  /* one complete type */
    1256        0x00,  /* nul terminator */
    1257        /* (Variant array value payload) */
    1258        0x00, 0x01, 0x02, 0x03,
    1259      /* (message body is zero-length) */
    1260    };
    1261    gsize size = sizeof (data);
    1262    GDBusMessage *message = NULL;
    1263    GError *local_error = NULL;
    1264  
    1265    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1266                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1267                                            &local_error);
    1268    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1269    g_assert_null (message);
    1270  
    1271    g_clear_error (&local_error);
    1272  }
    1273  
    1274  /* ---------------------------------------------------------------------------------------------------- */
    1275  
    1276  /* Test that an invalid header in a D-Bus message (specifically, containing a
    1277   * variant with a valid type signature that is too long to be a valid
    1278   * #GVariantType due to exceeding the array nesting limits) is gracefully
    1279   * handled with an error rather than a crash. */
    1280  static void
    1281  test_message_parse_over_long_signature_header (void)
    1282  {
    1283    const guint8 data[] = {
    1284      'l',  /* little-endian byte order */
    1285      0x02,  /* message type (method return) */
    1286      0x00,  /* message flags (none) */
    1287      0x01,  /* major protocol version */
    1288      0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1289      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1290      /* a{yv} of header fields:
    1291       * (things start to be invalid below here) */
    1292      0xa0, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1293        0x08,  /* array key (SIGNATURE) */
    1294        /* Variant array value: */
    1295        0x04,  /* signature length */
    1296        'g', 0x00, 0x20, 0x20,  /* one complete type plus some rubbish */
    1297        0x00,  /* nul terminator */
    1298        /* (Variant array value payload) */
    1299        /* Critically, this contains 128 nested ‘a’s, which exceeds
    1300         * %G_VARIANT_MAX_RECURSION_DEPTH. */
    1301        0xec,
    1302        'a', 'b', 'g', 'd', 'u', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
    1303        'd', 'd', 'd',
    1304        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1305        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1306        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1307        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1308        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1309        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1310        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1311        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1312        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1313        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1314        'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
    1315        'v',
    1316        /* first header length is a multiple of 8 so no padding is needed */
    1317        0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
    1318        /* Variant array value: */
    1319        0x01,  /* signature length */
    1320        'u',  /* one complete type */
    1321        0x00,  /* nul terminator */
    1322        /* (Variant array value payload) */
    1323        0x00, 0x01, 0x02, 0x03,
    1324      /* (message body is zero-length) */
    1325    };
    1326    gsize size = sizeof (data);
    1327    GDBusMessage *message = NULL;
    1328    GError *local_error = NULL;
    1329  
    1330    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1331                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1332                                            &local_error);
    1333    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1334    g_assert_null (message);
    1335  
    1336    g_clear_error (&local_error);
    1337  }
    1338  
    1339  /* ---------------------------------------------------------------------------------------------------- */
    1340  
    1341  /* Test that an invalid header in a D-Bus message (specifically, containing too
    1342   * many levels of nested variant) is gracefully handled with an error rather
    1343   * than a crash. */
    1344  static void
    1345  test_message_parse_deep_header_nesting (void)
    1346  {
    1347    const guint8 data[] = {
    1348      'l',  /* little-endian byte order */
    1349      0x02,  /* message type (method return) */
    1350      0x00,  /* message flags (none) */
    1351      0x01,  /* major protocol version */
    1352      0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1353      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1354      /* a{yv} of header fields:
    1355       * (things start to be invalid below here) */
    1356      0xd0, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1357        0x20,  /* array key (this is not currently a valid header field) */
    1358        /* Variant array value: */
    1359        0x01,  /* signature length */
    1360        'v',  /* one complete type */
    1361        0x00,  /* nul terminator */
    1362        /* (Variant array value payload) */
    1363        /* Critically, this contains 64 nested variants (minus two for the
    1364         * ‘arbitrary valid content’ below, but ignoring two for the `a{yv}`
    1365         * above), which in total exceeds %G_DBUS_MAX_TYPE_DEPTH. */
    1366        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1367        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1368        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1369        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1370        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1371        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1372        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1373        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1374        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1375        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1376        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1377        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1378        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1379        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1380        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1381        0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1382        /* Some arbitrary valid content inside the innermost variant: */
    1383        0x01, 'y', 0x00, 0xcc,
    1384        /* no padding needed as this header element length is a multiple of 8 */
    1385        0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
    1386        /* Variant array value: */
    1387        0x01,  /* signature length */
    1388        'u',  /* one complete type */
    1389        0x00,  /* nul terminator */
    1390        /* (Variant array value payload) */
    1391        0x00, 0x01, 0x02, 0x03,
    1392      /* (message body is zero-length) */
    1393    };
    1394    gsize size = sizeof (data);
    1395    GDBusMessage *message = NULL;
    1396    GError *local_error = NULL;
    1397  
    1398    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1399                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1400                                            &local_error);
    1401    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1402    g_assert_null (message);
    1403  
    1404    g_clear_error (&local_error);
    1405  }
    1406  
    1407  /* ---------------------------------------------------------------------------------------------------- */
    1408  
    1409  /* Test that an invalid body in a D-Bus message (specifically, containing too
    1410   * many levels of nested variant) is gracefully handled with an error rather
    1411   * than a crash. The set of bytes here are a modified version of the bytes from
    1412   * test_message_parse_deep_header_nesting(). */
    1413  static void
    1414  test_message_parse_deep_body_nesting (void)
    1415  {
    1416    const guint8 data[] = {
    1417      'l',  /* little-endian byte order */
    1418      0x02,  /* message type (method return) */
    1419      0x00,  /* message flags (none) */
    1420      0x01,  /* major protocol version */
    1421      0xc4, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1422      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1423      /* a{yv} of header fields: */
    1424      0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1425        0x08,  /* array key (SIGNATURE) */
    1426        /* Variant array value: */
    1427        0x01,  /* signature length */
    1428        'g',  /* one complete type */
    1429        0x00,  /* nul terminator */
    1430        /* (Variant array value payload) */
    1431        0x01, 'v', 0x00,
    1432        /* alignment padding before the next header array element, as structs must
    1433         * be 8-aligned: */
    1434        0x00,
    1435        0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
    1436        /* Variant array value: */
    1437        0x01,  /* signature length */
    1438        'u',  /* one complete type */
    1439        0x00,  /* nul terminator */
    1440        /* (Variant array value payload) */
    1441        0x00, 0x01, 0x02, 0x03,
    1442      /* Message body: over 64 levels of nested variant, which is not valid: */
    1443      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1444      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1445      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1446      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1447      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1448      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1449      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1450      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1451      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1452      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1453      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1454      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1455      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1456      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1457      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1458      0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
    1459      /* Some arbitrary valid content inside the innermost variant: */
    1460      0x01, 'y', 0x00, 0xcc,
    1461    };
    1462    gsize size = sizeof (data);
    1463    GDBusMessage *message = NULL;
    1464    GError *local_error = NULL;
    1465  
    1466    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1467                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1468                                            &local_error);
    1469    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1470    g_assert_null (message);
    1471  
    1472    g_clear_error (&local_error);
    1473  }
    1474  
    1475  /* ---------------------------------------------------------------------------------------------------- */
    1476  
    1477  static void
    1478  test_message_parse_truncated (void)
    1479  {
    1480    GDBusMessage *message = NULL;
    1481    GDBusMessage *message2 = NULL;
    1482    GVariantBuilder builder;
    1483    guchar *blob = NULL;
    1484    gsize size = 0;
    1485    GError *error = NULL;
    1486  
    1487    g_test_summary ("Test that truncated messages are properly rejected.");
    1488    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2528");
    1489  
    1490    message = g_dbus_message_new ();
    1491    g_variant_builder_init (&builder, G_VARIANT_TYPE ("(asbynqiuxtd)"));
    1492    g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
    1493    g_variant_builder_add (&builder, "s", "fourtytwo");
    1494    g_variant_builder_close (&builder);
    1495    g_variant_builder_add (&builder, "b", TRUE);
    1496    g_variant_builder_add (&builder, "y", 42);
    1497    g_variant_builder_add (&builder, "n", 42);
    1498    g_variant_builder_add (&builder, "q", 42);
    1499    g_variant_builder_add (&builder, "i", 42);
    1500    g_variant_builder_add (&builder, "u", 42);
    1501    g_variant_builder_add (&builder, "x", 42);
    1502    g_variant_builder_add (&builder, "t", 42);
    1503    g_variant_builder_add (&builder, "d", (gdouble) 42);
    1504  
    1505    g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
    1506    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH,
    1507                               g_variant_new_object_path ("/foo/bar"));
    1508    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
    1509                               g_variant_new_string ("Member"));
    1510    g_dbus_message_set_body (message, g_variant_builder_end (&builder));
    1511  
    1512    blob = g_dbus_message_to_blob (message, &size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1513    g_assert_no_error (error);
    1514  
    1515    g_clear_object (&message);
    1516  
    1517    /* Try parsing all possible prefixes of the full @blob. */
    1518    for (gsize i = 0; i < size; i++)
    1519      {
    1520        message2 = g_dbus_message_new_from_blob (blob, i, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1521        g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1522        g_assert_null (message2);
    1523        g_clear_error (&error);
    1524      }
    1525  
    1526    message2 = g_dbus_message_new_from_blob (blob, size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
    1527    g_assert_no_error (error);
    1528    g_assert_true (G_IS_DBUS_MESSAGE (message2));
    1529    g_clear_object (&message2);
    1530  
    1531    g_free (blob);
    1532  }
    1533  
    1534  static void
    1535  test_message_parse_empty_structure (void)
    1536  {
    1537    const guint8 data[] =
    1538      {
    1539        'l',  /* little-endian byte order */
    1540        0x02,  /* message type (method return) */
    1541        0x00,  /* message flags (none) */
    1542        0x01,  /* major protocol version */
    1543        0x08, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1544        0x00, 0x00, 0x00, 0x00,  /* message serial */
    1545        /* a{yv} of header fields */
    1546        0x20, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1547          0x01,  /* array key (PATH) */
    1548          0x01,  /* signature length */
    1549          'o',  /* type (OBJECT_PATH) */
    1550          0x00,  /* nul terminator */
    1551          0x05, 0x00, 0x00, 0x00, /* length 5 */
    1552          '/', 'p', 'a', 't', 'h', 0x00, 0x00, 0x00, /* string '/path' and padding */
    1553          0x03,  /* array key (MEMBER) */
    1554          0x01,  /* signature length */
    1555          's',  /* type (STRING) */
    1556          0x00,  /* nul terminator */
    1557          0x06, 0x00, 0x00, 0x00, /* length 6 */
    1558          'M', 'e', 'm', 'b', 'e', 'r', 0x00, 0x00, /* string 'Member' and padding */
    1559          0x08,  /* array key (SIGNATURE) */
    1560          0x01,  /* signature length */
    1561          'g',  /* type (SIGNATURE) */
    1562          0x00,  /* nul terminator */
    1563          0x03, /* length 3 */
    1564          'a', '(', ')', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* type 'a()' and padding */
    1565          0x08, 0x00, 0x00, 0x00, /* array length: 4 bytes */
    1566          0x00, 0x00, 0x00, 0x00, /* padding to 8 bytes */
    1567          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* array data */
    1568          0x00
    1569      };
    1570    gsize size = sizeof (data);
    1571    GDBusMessage *message = NULL;
    1572    GError *local_error = NULL;
    1573  
    1574    g_test_summary ("Test that empty structures are rejected when parsing.");
    1575    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2557");
    1576  
    1577    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1578                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1579                                            &local_error);
    1580    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1581    g_assert_cmpstr (local_error->message, ==, "Empty structures (tuples) are not allowed in D-Bus");
    1582    g_assert_null (message);
    1583  
    1584    g_clear_error (&local_error);
    1585  }
    1586  
    1587  static void
    1588  test_message_serialize_empty_structure (void)
    1589  {
    1590    GDBusMessage *message;
    1591    GVariantBuilder builder;
    1592    gsize size = 0;
    1593    GError *local_error = NULL;
    1594  
    1595    g_test_summary ("Test that empty structures are rejected when serializing.");
    1596    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2557");
    1597  
    1598    message = g_dbus_message_new ();
    1599    g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a())"));
    1600    g_variant_builder_open (&builder, G_VARIANT_TYPE ("a()"));
    1601    g_variant_builder_add (&builder, "()");
    1602    g_variant_builder_close (&builder);
    1603    g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
    1604    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH,
    1605                               g_variant_new_object_path ("/path"));
    1606    g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
    1607                               g_variant_new_string ("Member"));
    1608    g_dbus_message_set_body (message, g_variant_builder_end (&builder));
    1609  
    1610    g_dbus_message_to_blob (message, &size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
    1611    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1612    g_assert_cmpstr (local_error->message, ==, "Empty structures (tuples) are not allowed in D-Bus");
    1613  
    1614    g_clear_error (&local_error);
    1615    g_clear_object (&message);
    1616  }
    1617  
    1618  static void
    1619  test_message_parse_missing_header (void)
    1620  {
    1621    const guint8 data[] = {
    1622      'l',  /* little-endian byte order */
    1623      0x01,  /* message type (method call) */
    1624      0x00,  /* message flags (none) */
    1625      0x01,  /* major protocol version */
    1626      0x12, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1627      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1628      /* a{yv} of header fields: */
    1629      0x24, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1630        0x01,  /* array key (PATH, required for method call messages) */
    1631        /* Variant array value: */
    1632        0x01,  /* signature length */
    1633        'o',  /* one complete type */
    1634        0x00,  /* nul terminator */
    1635        /* (Variant array value payload) */
    1636        0x01, 0x00, 0x00, 0x00,
    1637        '/', 0x00, 0x00, 0x00,
    1638        0x00, 0x00, 0x00, 0x00,
    1639        0x30,  /* array key (MEMBER, required for method call messages; CORRUPTED from 0x03) */
    1640        /* Variant array value: */
    1641        0x01,  /* signature length */
    1642        's',  /* one complete type */
    1643        0x00,  /* nul terminator */
    1644        /* (Variant array value payload) */
    1645        0x03, 0x00, 0x00, 0x00,
    1646        'H', 'e', 'y', 0x00,
    1647        0x00, 0x00, 0x00, 0x00,
    1648        0x08,  /* array key (SIGNATURE) */
    1649        /* Variant array value: */
    1650        0x01,  /* signature length */
    1651        'g',  /* one complete type */
    1652        0x00,  /* nul terminator */
    1653        /* (Variant array value payload) */
    1654        0x02, 's', 's', 0x00,
    1655      /* Some arbitrary valid content inside the message body: */
    1656      0x03, 0x00, 0x00, 0x00,
    1657      'h', 'e', 'y', 0x00,
    1658      0x05, 0x00, 0x00, 0x00,
    1659      't', 'h', 'e', 'r', 'e', 0x00
    1660    };
    1661  
    1662    gsize size = sizeof (data);
    1663    GDBusMessage *message = NULL;
    1664    GError *local_error = NULL;
    1665  
    1666    g_test_summary ("Test that missing (required) headers prompt an error.");
    1667    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3061");
    1668  
    1669    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1670                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1671                                            &local_error);
    1672    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1673    g_assert_null (message);
    1674  
    1675    g_clear_error (&local_error);
    1676  }
    1677  
    1678  static void
    1679  test_message_parse_invalid_header_type (void)
    1680  {
    1681    const guint8 data[] = {
    1682      'l',  /* little-endian byte order */
    1683      0x01,  /* message type (method call) */
    1684      0x00,  /* message flags (none) */
    1685      0x01,  /* major protocol version */
    1686      0x12, 0x00, 0x00, 0x00,  /* body length (in bytes) */
    1687      0x20, 0x20, 0x20, 0x20,  /* message serial */
    1688      /* a{yv} of header fields: */
    1689      0x24, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
    1690        0x01,  /* array key (PATH, required for method call messages) */
    1691        /* Variant array value: */
    1692        0x01,  /* signature length */
    1693        'o',  /* one complete type */
    1694        0x00,  /* nul terminator */
    1695        /* (Variant array value payload) */
    1696        0x01, 0x00, 0x00, 0x00,
    1697        '/', 0x00, 0x00, 0x00,
    1698        0x00, 0x00, 0x00, 0x00,
    1699        0x03,  /* array key (MEMBER, required for method call messages) */
    1700        /* Variant array value: */
    1701        0x01,  /* signature length */
    1702        't',  /* one complete type; CORRUPTED, MEMBER should be 's' */
    1703        0x00,  /* nul terminator */
    1704        /* (Padding to 64-bit alignment of 't)' */
    1705        0x00, 0x00, 0x00, 0x00,
    1706        /* (Variant array value payload) */
    1707        'H', 'e', 'y', 0x00,
    1708        0x00, 0x00, 0x00, 0x00,
    1709        0x08,  /* array key (SIGNATURE) */
    1710        /* Variant array value: */
    1711        0x01,  /* signature length */
    1712        'g',  /* one complete type */
    1713        0x00,  /* nul terminator */
    1714        /* (Variant array value payload) */
    1715        0x02, 's', 's', 0x00,
    1716      /* Some arbitrary valid content inside the message body: */
    1717      0x03, 0x00, 0x00, 0x00,
    1718      'h', 'e', 'y', 0x00,
    1719      0x05, 0x00, 0x00, 0x00,
    1720      't', 'h', 'e', 'r', 'e', 0x00
    1721    };
    1722  
    1723    gsize size = sizeof (data);
    1724    GDBusMessage *message = NULL;
    1725    GError *local_error = NULL;
    1726  
    1727    g_test_summary ("Test that the type of well-known headers is checked.");
    1728    g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3061");
    1729  
    1730    message = g_dbus_message_new_from_blob ((guchar *) data, size,
    1731                                            G_DBUS_CAPABILITY_FLAGS_NONE,
    1732                                            &local_error);
    1733    g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
    1734    g_assert_null (message);
    1735  
    1736    g_clear_error (&local_error);
    1737  }
    1738  
    1739  /* ---------------------------------------------------------------------------------------------------- */
    1740  
    1741  int
    1742  main (int   argc,
    1743        char *argv[])
    1744  {
    1745    g_setenv ("LC_ALL", "C", TRUE);
    1746    setlocale (LC_ALL, "C");
    1747  
    1748    g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
    1749  
    1750    g_test_add_func ("/gdbus/message-serialize/basic",
    1751                     test_message_serialize_basic);
    1752    g_test_add_func ("/gdbus/message-serialize/complex",
    1753                     test_message_serialize_complex);
    1754    g_test_add_func ("/gdbus/message-serialize/invalid",
    1755                     test_message_serialize_invalid);
    1756    g_test_add_func ("/gdbus/message-serialize/header-checks",
    1757                     test_message_serialize_header_checks);
    1758    g_test_add_func ("/gdbus/message-serialize/double-array",
    1759                     test_message_serialize_double_array);
    1760    g_test_add_func ("/gdbus/message-serialize/empty-structure",
    1761                     test_message_serialize_empty_structure);
    1762  
    1763    g_test_add_func ("/gdbus/message-parse/empty-arrays-of-arrays",
    1764                     test_message_parse_empty_arrays_of_arrays);
    1765    g_test_add_func ("/gdbus/message-parse/non-signature-header",
    1766                     test_message_parse_non_signature_header);
    1767    g_test_add_func ("/gdbus/message-parse/empty-signature-header",
    1768                     test_message_parse_empty_signature_header);
    1769    g_test_add_func ("/gdbus/message-parse/multiple-signature-header",
    1770                     test_message_parse_multiple_signature_header);
    1771    g_test_add_func ("/gdbus/message-parse/over-long-signature-header",
    1772                     test_message_parse_over_long_signature_header);
    1773    g_test_add_func ("/gdbus/message-parse/deep-header-nesting",
    1774                     test_message_parse_deep_header_nesting);
    1775    g_test_add_func ("/gdbus/message-parse/deep-body-nesting",
    1776                     test_message_parse_deep_body_nesting);
    1777    g_test_add_func ("/gdbus/message-parse/truncated",
    1778                     test_message_parse_truncated);
    1779    g_test_add_func ("/gdbus/message-parse/empty-structure",
    1780                     test_message_parse_empty_structure);
    1781    g_test_add_func ("/gdbus/message-parse/missing-header",
    1782                     test_message_parse_missing_header);
    1783    g_test_add_func ("/gdbus/message-parse/invalid-header-type",
    1784                     test_message_parse_invalid_header_type);
    1785  
    1786    return g_test_run();
    1787  }