kdbus: Fixup signal subscription
[platform/upstream/glib.git] / 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 we can't serialize messages with an INVALID header
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_INVALID, 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, ==, "Cannot serialize message: SIGNAL message: INVALID header field supplied");
925   g_assert_null (blob);
926
927   g_clear_error (&error);
928   g_clear_object (&message);
929
930   /*
931    * check that we can't serialize messages with various fields set to incorrectly typed values
932    */
933   const struct
934     {
935       GDBusMessageHeaderField field;
936       const char *invalid_value;  /* as a GVariant in text form */
937       const char *expected_error_message;
938     }
939   field_type_tests[] =
940     {
941       {
942         G_DBUS_MESSAGE_HEADER_FIELD_PATH,
943         "'/correct/value/but/wrong/type'",
944         "Cannot serialize message: SIGNAL message: PATH header field is invalid; expected a value of type â€˜o’"
945       },
946       {
947         G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE,
948         "@u 5",
949         "Cannot serialize message: SIGNAL message: INTERFACE header field is invalid; expected a value of type â€˜s’"
950       },
951       {
952         G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE,
953         "'valid type, but not an interface name'",
954         "Cannot serialize message: SIGNAL message: INTERFACE header field does not contain a valid interface name"
955       },
956       {
957         G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
958         "@u 5",
959         "Cannot serialize message: SIGNAL message: MEMBER header field is invalid; expected a value of type â€˜s’"
960       },
961       {
962         G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
963         "'valid type, but not a member name'",
964         "Cannot serialize message: SIGNAL message: MEMBER header field does not contain a valid member name"
965       },
966       {
967         G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME,
968         "@u 5",
969         "Cannot serialize message: SIGNAL message: ERROR_NAME header field is invalid; expected a value of type â€˜s’"
970       },
971       {
972         G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME,
973         "'valid type, but not an error name'",
974         "Cannot serialize message: SIGNAL message: ERROR_NAME header field does not contain a valid error name"
975       },
976       {
977         G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL,
978         "'oops'",
979         "Cannot serialize message: SIGNAL message: REPLY_SERIAL header field is invalid; expected a value of type â€˜u’"
980       },
981       {
982         G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION,
983         "@u 5",
984         "Cannot serialize message: SIGNAL message: DESTINATION header field is invalid; expected a value of type â€˜s’"
985       },
986       {
987         G_DBUS_MESSAGE_HEADER_FIELD_SENDER,
988         "@u 5",
989         "Cannot serialize message: SIGNAL message: SENDER header field is invalid; expected a value of type â€˜s’"
990       },
991       {
992         G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE,
993         "false",
994         "Cannot serialize message: SIGNAL message: SIGNATURE header field is invalid; expected a value of type â€˜g’"
995       },
996       {
997         G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS,
998         "'five'",
999         "Cannot serialize message: SIGNAL message: NUM_UNIX_FDS header field is invalid; expected a value of type â€˜u’"
1000       },
1001     };
1002
1003   for (size_t i = 0; i < G_N_ELEMENTS (field_type_tests); i++)
1004     {
1005       message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
1006       g_dbus_message_set_header (message, field_type_tests[i].field, g_variant_new_parsed (field_type_tests[i].invalid_value));
1007       blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1008
1009       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1010       g_assert_cmpstr (error->message, ==, field_type_tests[i].expected_error_message);
1011       g_assert_null (blob);
1012
1013       g_clear_error (&error);
1014       g_clear_object (&message);
1015     }
1016
1017   /*
1018    * check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
1019    */
1020   message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
1021   /* ----- */
1022   /* interface NULL => error */
1023   g_dbus_message_set_interface (message, NULL);
1024   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1025   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1026   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: INTERFACE header field is missing or invalid");
1027   g_clear_error (&error);
1028   g_assert_null (blob);
1029   /* interface reserved value => error */
1030   g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
1031   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1032   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1033   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
1034   g_clear_error (&error);
1035   g_assert_null (blob);
1036   /* reset interface */
1037   g_dbus_message_set_interface (message, "The.Interface");
1038   /* ----- */
1039   /* path NULL => error */
1040   g_dbus_message_set_path (message, NULL);
1041   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1042   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1043   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH header field is missing or invalid");
1044   g_clear_error (&error);
1045   g_assert_null (blob);
1046   /* path reserved value => error */
1047   g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
1048   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1049   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1050   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH header field is using the reserved value /org/freedesktop/DBus/Local");
1051   g_clear_error (&error);
1052   g_assert_null (blob);
1053   /* reset path */
1054   g_dbus_message_set_path (message, "/the/path");
1055   /* ----- */
1056   /* member NULL => error */
1057   g_dbus_message_set_member (message, NULL);
1058   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1059   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1060   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: MEMBER header field is missing or invalid");
1061   g_clear_error (&error);
1062   g_assert_null (blob);
1063   /* reset member */
1064   g_dbus_message_set_member (message, "TheMember");
1065   /* ----- */
1066   /* done */
1067   g_object_unref (message);
1068
1069   /*
1070    * check that we can't serialize method call messages with PATH or MEMBER unset
1071    */
1072   message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
1073   /* ----- */
1074   /* path NULL => error */
1075   g_dbus_message_set_path (message, NULL);
1076   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1077   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1078   g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH header field is missing or invalid");
1079   g_clear_error (&error);
1080   g_assert_null (blob);
1081   /* reset path */
1082   g_dbus_message_set_path (message, "/the/path");
1083   /* ----- */
1084   /* member NULL => error */
1085   g_dbus_message_set_member (message, NULL);
1086   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1087   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1088   g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: MEMBER header field is missing or invalid");
1089   g_clear_error (&error);
1090   g_assert_null (blob);
1091   /* reset member */
1092   g_dbus_message_set_member (message, "TheMember");
1093   /* ----- */
1094   /* done */
1095   g_object_unref (message);
1096
1097   /*
1098    * check that we can't serialize method reply messages with REPLY_SERIAL unset
1099    */
1100   message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
1101   g_dbus_message_set_serial (message, 42);
1102   /* method reply */
1103   reply = g_dbus_message_new_method_reply (message);
1104   g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
1105   g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
1106   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1107   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1108   g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid");
1109   g_clear_error (&error);
1110   g_assert_null (blob);
1111   g_object_unref (reply);
1112   /* method error - first nuke ERROR_NAME, then REPLY_SERIAL */
1113   reply = g_dbus_message_new_method_error (message, "Some.Error.Name", "the message");
1114   g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
1115   /* nuke ERROR_NAME */
1116   g_dbus_message_set_error_name (reply, NULL);
1117   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1118   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1119   g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: ERROR_NAME header field is missing or invalid");
1120   g_clear_error (&error);
1121   g_assert_null (blob);
1122   /* reset ERROR_NAME */
1123   g_dbus_message_set_error_name (reply, "Some.Error.Name");
1124   /* nuke REPLY_SERIAL */
1125   g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
1126   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1127   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1128   g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL header field is missing or invalid");
1129   g_clear_error (&error);
1130   g_assert_null (blob);
1131   g_object_unref (reply);
1132   g_object_unref (message);
1133 }
1134
1135 static void
1136 test_message_serialize_header_checks_valid (void)
1137 {
1138   GDBusMessage *message = NULL, *reply = NULL;
1139   GError *local_error = NULL;
1140   guchar *blob;
1141   gsize blob_size;
1142
1143   g_test_summary ("Test that validation allows well-formed messages of all the different types");
1144
1145   /* Method call */
1146   message = g_dbus_message_new_method_call ("Some.Name", "/the/path", "org.some.Interface", "TheMethod");
1147   g_dbus_message_set_serial (message, 666);
1148   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1149   g_assert_no_error (local_error);
1150   g_assert_nonnull (blob);
1151   g_free (blob);
1152
1153   /* Method return */
1154   reply = g_dbus_message_new_method_reply (message);
1155   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1156   g_assert_no_error (local_error);
1157   g_assert_nonnull (blob);
1158   g_free (blob);
1159   g_clear_object (&reply);
1160
1161   /* Error */
1162   reply = g_dbus_message_new_method_error (message, "Error.Name", "Some error message");
1163   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1164   g_assert_no_error (local_error);
1165   g_assert_nonnull (blob);
1166   g_free (blob);
1167
1168   g_clear_object (&reply);
1169   g_clear_object (&message);
1170
1171   /* Signal */
1172   message = g_dbus_message_new_signal ("/the/path", "org.some.Interface", "SignalName");
1173   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1174   g_assert_no_error (local_error);
1175   g_assert_nonnull (blob);
1176   g_free (blob);
1177   g_clear_object (&message);
1178
1179   /* Also check that an unknown message type is allowed */
1180   message = g_dbus_message_new ();
1181   g_dbus_message_set_message_type (message, 123);
1182   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1183   g_assert_no_error (local_error);
1184   g_assert_nonnull (blob);
1185   g_free (blob);
1186   g_clear_object (&message);
1187
1188   /* Even one with a well-defined field on it */
1189   message = g_dbus_message_new ();
1190   g_dbus_message_set_message_type (message, 123);
1191   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS, g_variant_new_uint32 (0));
1192   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1193   g_assert_no_error (local_error);
1194   g_assert_nonnull (blob);
1195   g_free (blob);
1196   g_clear_object (&message);
1197 }
1198
1199 /* ---------------------------------------------------------------------------------------------------- */
1200
1201 static void
1202 test_message_parse_empty_arrays_of_arrays (void)
1203 {
1204   GVariant *body;
1205   GError *error = NULL;
1206
1207   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=673612");
1208   /* These three-element array of empty arrays were previously read back as a
1209    * two-element array of empty arrays, due to sometimes erroneously skipping
1210    * four bytes to align for the eight-byte-aligned grandchild types (x and
1211    * dict_entry).
1212    */
1213   body = g_variant_parse (G_VARIANT_TYPE ("(aaax)"),
1214       "([@aax [], [], []],)", NULL, NULL, &error);
1215   g_assert_no_error (error);
1216   check_serialization (body,
1217       "value 0:   array:\n"
1218       "    array:\n"
1219       "    array:\n"
1220       "    array:\n");
1221   g_variant_unref (body);
1222
1223   body = g_variant_parse (G_VARIANT_TYPE ("(aaa{uu})"),
1224       "([@aa{uu} [], [], []],)", NULL, NULL, &error);
1225   g_assert_no_error (error);
1226   check_serialization (body,
1227       "value 0:   array:\n"
1228       "    array:\n"
1229       "    array:\n"
1230       "    array:\n");
1231   g_variant_unref (body);
1232
1233   /* Due to the same bug, g_dbus_message_new_from_blob() would fail for this
1234    * message because it would try to read past the end of the string. Hence,
1235    * sending this to an application would make it fall off the bus. */
1236   body = g_variant_parse (G_VARIANT_TYPE ("(a(aa{sv}as))"),
1237       "([ ([], []),"
1238       "   ([], []),"
1239       "   ([], [])],)", NULL, NULL, &error);
1240   g_assert_no_error (error);
1241   check_serialization (body,
1242       "value 0:   array:\n"
1243       "    struct:\n"
1244       "      array:\n"
1245       "      array:\n"
1246       "    struct:\n"
1247       "      array:\n"
1248       "      array:\n"
1249       "    struct:\n"
1250       "      array:\n"
1251       "      array:\n");
1252   g_variant_unref (body);
1253 }
1254
1255 /* ---------------------------------------------------------------------------------------------------- */
1256
1257 static void
1258 test_message_serialize_double_array (void)
1259 {
1260   GVariantBuilder builder;
1261   GVariant *body;
1262
1263   g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=732754");
1264
1265   g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
1266   g_variant_builder_add (&builder, "d", (gdouble)0.0);
1267   g_variant_builder_add (&builder, "d", (gdouble)8.0);
1268   g_variant_builder_add (&builder, "d", (gdouble)22.0);
1269   g_variant_builder_add (&builder, "d", (gdouble)0.0);
1270   body = g_variant_new ("(@ad)", g_variant_builder_end (&builder));
1271   check_serialization (body,
1272       "value 0:   array:\n"
1273       "    double: 0.000000\n"
1274       "    double: 8.000000\n"
1275       "    double: 22.000000\n"
1276       "    double: 0.000000\n");
1277 }
1278
1279 /* ---------------------------------------------------------------------------------------------------- */
1280
1281 /* Test that an invalid header in a D-Bus message (specifically, with a type
1282  * which doesn’t match what’s expected for the given header) is gracefully
1283  * handled with an error rather than a crash. */
1284 static void
1285 test_message_parse_non_signature_header (void)
1286 {
1287   const guint8 data[] = {
1288     'l',  /* little-endian byte order */
1289     0x02,  /* message type (method return) */
1290     0x00,  /* message flags (none) */
1291     0x01,  /* major protocol version */
1292     0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1293     0x00, 0x00, 0x00, 0xbc,  /* message serial */
1294     /* a{yv} of header fields:
1295      * (things start to be invalid below here) */
1296     0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1297       0x08, /* array key (SIGNATURE) */
1298       /* Variant array value: */
1299       0x04, /* signature length */
1300       'd', 0x00, 0x00, 'F',  /* signature (invalid) */
1301       0x00,  /* nul terminator */
1302       /* (Variant array value payload missing) */
1303       /* alignment padding before the next header array element, as structs must
1304        * be 8-aligned: */
1305       0x00,
1306       0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
1307       /* Variant array value: */
1308       0x01,  /* signature length */
1309       'u',  /* one complete type */
1310       0x00,  /* nul terminator */
1311       /* (Variant array value payload) */
1312       0x00, 0x01, 0x02, 0x03,
1313     /* (message body is zero-length) */
1314   };
1315   gsize size = sizeof (data);
1316   GDBusMessage *message = NULL;
1317   GError *local_error = NULL;
1318
1319   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1320                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1321                                           &local_error);
1322   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1323   g_assert_null (message);
1324
1325   g_clear_error (&local_error);
1326 }
1327
1328 /* ---------------------------------------------------------------------------------------------------- */
1329
1330 /* Test that an invalid header in a D-Bus message (specifically, containing a
1331  * variant with an empty type signature) is gracefully handled with an error
1332  * rather than a crash. */
1333 static void
1334 test_message_parse_empty_signature_header (void)
1335 {
1336   const guint8 data[] = {
1337     'l',  /* little-endian byte order */
1338     0x02,  /* message type (method return) */
1339     0x00,  /* message flags (none) */
1340     0x01,  /* major protocol version */
1341     0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1342     0x20, 0x20, 0x20, 0x20,  /* message serial */
1343     /* a{yv} of header fields:
1344      * (things start to be invalid below here) */
1345     0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1346       0x20, /* array key (this is not currently a valid header field) */
1347       /* Variant array value: */
1348       0x00, /* signature length */
1349       0x00,  /* nul terminator */
1350       /* (Variant array value payload missing) */
1351       /* alignment padding before the next header array element, as structs must
1352        * be 8-aligned: */
1353       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1354       0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
1355       /* Variant array value: */
1356       0x01,  /* signature length */
1357       'u',  /* one complete type */
1358       0x00,  /* nul terminator */
1359       /* (Variant array value payload) */
1360       0x00, 0x01, 0x02, 0x03,
1361     /* (message body is zero-length) */
1362   };
1363   gsize size = sizeof (data);
1364   GDBusMessage *message = NULL;
1365   GError *local_error = NULL;
1366
1367   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1368                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1369                                           &local_error);
1370   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1371   g_assert_null (message);
1372
1373   g_clear_error (&local_error);
1374 }
1375
1376 /* ---------------------------------------------------------------------------------------------------- */
1377
1378 /* Test that an invalid header in a D-Bus message (specifically, containing a
1379  * variant with a type signature containing multiple complete types) is
1380  * gracefully handled with an error rather than a crash. */
1381 static void
1382 test_message_parse_multiple_signature_header (void)
1383 {
1384   const guint8 data[] = {
1385     'l',  /* little-endian byte order */
1386     0x02,  /* message type (method return) */
1387     0x00,  /* message flags (none) */
1388     0x01,  /* major protocol version */
1389     0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1390     0x20, 0x20, 0x20, 0x20,  /* message serial */
1391     /* a{yv} of header fields:
1392      * (things start to be invalid below here) */
1393     0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1394       0x20, /* array key (this is not currently a valid header field) */
1395       /* Variant array value: */
1396       0x02, /* signature length */
1397       'b', 'b',  /* two complete types */
1398       0x00,  /* nul terminator */
1399       /* (Variant array value payload missing) */
1400       /* alignment padding before the next header array element, as structs must
1401        * be 8-aligned: */
1402       0x00, 0x00, 0x00,
1403       0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
1404       /* Variant array value: */
1405       0x01,  /* signature length */
1406       'u',  /* one complete type */
1407       0x00,  /* nul terminator */
1408       /* (Variant array value payload) */
1409       0x00, 0x01, 0x02, 0x03,
1410     /* (message body is zero-length) */
1411   };
1412   gsize size = sizeof (data);
1413   GDBusMessage *message = NULL;
1414   GError *local_error = NULL;
1415
1416   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1417                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1418                                           &local_error);
1419   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1420   g_assert_null (message);
1421
1422   g_clear_error (&local_error);
1423 }
1424
1425 /* ---------------------------------------------------------------------------------------------------- */
1426
1427 /* Test that an invalid header in a D-Bus message (specifically, containing a
1428  * variant with a valid type signature that is too long to be a valid
1429  * #GVariantType due to exceeding the array nesting limits) is gracefully
1430  * handled with an error rather than a crash. */
1431 static void
1432 test_message_parse_over_long_signature_header (void)
1433 {
1434   const guint8 data[] = {
1435     'l',  /* little-endian byte order */
1436     0x02,  /* message type (method return) */
1437     0x00,  /* message flags (none) */
1438     0x01,  /* major protocol version */
1439     0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1440     0x20, 0x20, 0x20, 0x20,  /* message serial */
1441     /* a{yv} of header fields:
1442      * (things start to be invalid below here) */
1443     0xa0, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1444       0x08,  /* array key (SIGNATURE) */
1445       /* Variant array value: */
1446       0x04,  /* signature length */
1447       'g', 0x00, 0x20, 0x20,  /* one complete type plus some rubbish */
1448       0x00,  /* nul terminator */
1449       /* (Variant array value payload) */
1450       /* Critically, this contains 128 nested â€˜a’s, which exceeds
1451        * %G_VARIANT_MAX_RECURSION_DEPTH. */
1452       0xec,
1453       'a', 'b', 'g', 'd', 'u', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
1454       'd', 'd', 'd',
1455       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1456       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1457       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1458       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1459       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1460       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1461       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1462       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1463       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1464       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1465       'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1466       'v',
1467       /* first header length is a multiple of 8 so no padding is needed */
1468       0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
1469       /* Variant array value: */
1470       0x01,  /* signature length */
1471       'u',  /* one complete type */
1472       0x00,  /* nul terminator */
1473       /* (Variant array value payload) */
1474       0x00, 0x01, 0x02, 0x03,
1475     /* (message body is zero-length) */
1476   };
1477   gsize size = sizeof (data);
1478   GDBusMessage *message = NULL;
1479   GError *local_error = NULL;
1480
1481   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1482                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1483                                           &local_error);
1484   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1485   g_assert_null (message);
1486
1487   g_clear_error (&local_error);
1488 }
1489
1490 /* ---------------------------------------------------------------------------------------------------- */
1491
1492 /* Test that an invalid header in a D-Bus message (specifically, containing too
1493  * many levels of nested variant) is gracefully handled with an error rather
1494  * than a crash. */
1495 static void
1496 test_message_parse_deep_header_nesting (void)
1497 {
1498   const guint8 data[] = {
1499     'l',  /* little-endian byte order */
1500     0x02,  /* message type (method return) */
1501     0x00,  /* message flags (none) */
1502     0x01,  /* major protocol version */
1503     0x00, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1504     0x20, 0x20, 0x20, 0x20,  /* message serial */
1505     /* a{yv} of header fields:
1506      * (things start to be invalid below here) */
1507     0xd0, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1508       0x20,  /* array key (this is not currently a valid header field) */
1509       /* Variant array value: */
1510       0x01,  /* signature length */
1511       'v',  /* one complete type */
1512       0x00,  /* nul terminator */
1513       /* (Variant array value payload) */
1514       /* Critically, this contains 64 nested variants (minus two for the
1515        * â€˜arbitrary valid content’ below, but ignoring two for the `a{yv}`
1516        * above), which in total exceeds %G_DBUS_MAX_TYPE_DEPTH. */
1517       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1518       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1519       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1520       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1521       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1522       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1523       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1524       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1525       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1526       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1527       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1528       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1529       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1530       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1531       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1532       0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1533       /* Some arbitrary valid content inside the innermost variant: */
1534       0x01, 'y', 0x00, 0xcc,
1535       /* no padding needed as this header element length is a multiple of 8 */
1536       0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
1537       /* Variant array value: */
1538       0x01,  /* signature length */
1539       'u',  /* one complete type */
1540       0x00,  /* nul terminator */
1541       /* (Variant array value payload) */
1542       0x00, 0x01, 0x02, 0x03,
1543     /* (message body is zero-length) */
1544   };
1545   gsize size = sizeof (data);
1546   GDBusMessage *message = NULL;
1547   GError *local_error = NULL;
1548
1549   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1550                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1551                                           &local_error);
1552   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1553   g_assert_null (message);
1554
1555   g_clear_error (&local_error);
1556 }
1557
1558 /* ---------------------------------------------------------------------------------------------------- */
1559
1560 /* Test that an invalid body in a D-Bus message (specifically, containing too
1561  * many levels of nested variant) is gracefully handled with an error rather
1562  * than a crash. The set of bytes here are a modified version of the bytes from
1563  * test_message_parse_deep_header_nesting(). */
1564 static void
1565 test_message_parse_deep_body_nesting (void)
1566 {
1567   const guint8 data[] = {
1568     'l',  /* little-endian byte order */
1569     0x02,  /* message type (method return) */
1570     0x00,  /* message flags (none) */
1571     0x01,  /* major protocol version */
1572     0xc4, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1573     0x20, 0x20, 0x20, 0x20,  /* message serial */
1574     /* a{yv} of header fields: */
1575     0x10, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1576       0x08,  /* array key (SIGNATURE) */
1577       /* Variant array value: */
1578       0x01,  /* signature length */
1579       'g',  /* one complete type */
1580       0x00,  /* nul terminator */
1581       /* (Variant array value payload) */
1582       0x01, 'v', 0x00,
1583       /* alignment padding before the next header array element, as structs must
1584        * be 8-aligned: */
1585       0x00,
1586       0x05,  /* array key (REPLY_SERIAL, required for method return messages) */
1587       /* Variant array value: */
1588       0x01,  /* signature length */
1589       'u',  /* one complete type */
1590       0x00,  /* nul terminator */
1591       /* (Variant array value payload) */
1592       0x00, 0x01, 0x02, 0x03,
1593     /* Message body: over 64 levels of nested variant, which is not valid: */
1594     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1595     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1596     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1597     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1598     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1599     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1600     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1601     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1602     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1603     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1604     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1605     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1606     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1607     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1608     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1609     0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1610     /* Some arbitrary valid content inside the innermost variant: */
1611     0x01, 'y', 0x00, 0xcc,
1612   };
1613   gsize size = sizeof (data);
1614   GDBusMessage *message = NULL;
1615   GError *local_error = NULL;
1616
1617   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1618                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1619                                           &local_error);
1620   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1621   g_assert_null (message);
1622
1623   g_clear_error (&local_error);
1624 }
1625
1626 /* ---------------------------------------------------------------------------------------------------- */
1627
1628 static void
1629 test_message_parse_truncated (void)
1630 {
1631   GDBusMessage *message = NULL;
1632   GDBusMessage *message2 = NULL;
1633   GVariantBuilder builder;
1634   guchar *blob = NULL;
1635   gsize size = 0;
1636   GError *error = NULL;
1637
1638   g_test_summary ("Test that truncated messages are properly rejected.");
1639   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2528");
1640
1641   message = g_dbus_message_new ();
1642   g_variant_builder_init (&builder, G_VARIANT_TYPE ("(asbynqiuxtd)"));
1643   g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
1644   g_variant_builder_add (&builder, "s", "fourtytwo");
1645   g_variant_builder_close (&builder);
1646   g_variant_builder_add (&builder, "b", TRUE);
1647   g_variant_builder_add (&builder, "y", 42);
1648   g_variant_builder_add (&builder, "n", 42);
1649   g_variant_builder_add (&builder, "q", 42);
1650   g_variant_builder_add (&builder, "i", 42);
1651   g_variant_builder_add (&builder, "u", 42);
1652   g_variant_builder_add (&builder, "x", 42);
1653   g_variant_builder_add (&builder, "t", 42);
1654   g_variant_builder_add (&builder, "d", (gdouble) 42);
1655
1656   g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
1657   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH,
1658                              g_variant_new_object_path ("/foo/bar"));
1659   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
1660                              g_variant_new_string ("Member"));
1661   g_dbus_message_set_body (message, g_variant_builder_end (&builder));
1662
1663   blob = g_dbus_message_to_blob (message, &size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1664   g_assert_no_error (error);
1665
1666   g_clear_object (&message);
1667
1668   /* Try parsing all possible prefixes of the full @blob. */
1669   for (gsize i = 0; i < size; i++)
1670     {
1671       message2 = g_dbus_message_new_from_blob (blob, i, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1672       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1673       g_assert_null (message2);
1674       g_clear_error (&error);
1675     }
1676
1677   message2 = g_dbus_message_new_from_blob (blob, size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1678   g_assert_no_error (error);
1679   g_assert_true (G_IS_DBUS_MESSAGE (message2));
1680   g_clear_object (&message2);
1681
1682   g_free (blob);
1683 }
1684
1685 static void
1686 test_message_parse_empty_structure (void)
1687 {
1688   const guint8 data[] =
1689     {
1690       'l',  /* little-endian byte order */
1691       0x02,  /* message type (method return) */
1692       0x00,  /* message flags (none) */
1693       0x01,  /* major protocol version */
1694       0x08, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1695       0x00, 0x00, 0x00, 0x00,  /* message serial */
1696       /* a{yv} of header fields */
1697       0x20, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1698         0x01,  /* array key (PATH) */
1699         0x01,  /* signature length */
1700         'o',  /* type (OBJECT_PATH) */
1701         0x00,  /* nul terminator */
1702         0x05, 0x00, 0x00, 0x00, /* length 5 */
1703         '/', 'p', 'a', 't', 'h', 0x00, 0x00, 0x00, /* string '/path' and padding */
1704         0x03,  /* array key (MEMBER) */
1705         0x01,  /* signature length */
1706         's',  /* type (STRING) */
1707         0x00,  /* nul terminator */
1708         0x06, 0x00, 0x00, 0x00, /* length 6 */
1709         'M', 'e', 'm', 'b', 'e', 'r', 0x00, 0x00, /* string 'Member' and padding */
1710         0x08,  /* array key (SIGNATURE) */
1711         0x01,  /* signature length */
1712         'g',  /* type (SIGNATURE) */
1713         0x00,  /* nul terminator */
1714         0x03, /* length 3 */
1715         'a', '(', ')', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* type 'a()' and padding */
1716         0x08, 0x00, 0x00, 0x00, /* array length: 4 bytes */
1717         0x00, 0x00, 0x00, 0x00, /* padding to 8 bytes */
1718         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* array data */
1719         0x00
1720     };
1721   gsize size = sizeof (data);
1722   GDBusMessage *message = NULL;
1723   GError *local_error = NULL;
1724
1725   g_test_summary ("Test that empty structures are rejected when parsing.");
1726   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2557");
1727
1728   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1729                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1730                                           &local_error);
1731   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1732   g_assert_cmpstr (local_error->message, ==, "Empty structures (tuples) are not allowed in D-Bus");
1733   g_assert_null (message);
1734
1735   g_clear_error (&local_error);
1736 }
1737
1738 static void
1739 test_message_serialize_empty_structure (void)
1740 {
1741   GDBusMessage *message;
1742   GVariantBuilder builder;
1743   gsize size = 0;
1744   GError *local_error = NULL;
1745
1746   g_test_summary ("Test that empty structures are rejected when serializing.");
1747   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2557");
1748
1749   message = g_dbus_message_new ();
1750   g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a())"));
1751   g_variant_builder_open (&builder, G_VARIANT_TYPE ("a()"));
1752   g_variant_builder_add (&builder, "()");
1753   g_variant_builder_close (&builder);
1754   g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
1755   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH,
1756                              g_variant_new_object_path ("/path"));
1757   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER,
1758                              g_variant_new_string ("Member"));
1759   g_dbus_message_set_body (message, g_variant_builder_end (&builder));
1760
1761   g_dbus_message_to_blob (message, &size, G_DBUS_CAPABILITY_FLAGS_NONE, &local_error);
1762   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1763   g_assert_cmpstr (local_error->message, ==, "Empty structures (tuples) are not allowed in D-Bus");
1764
1765   g_clear_error (&local_error);
1766   g_clear_object (&message);
1767 }
1768
1769 static void
1770 test_message_parse_missing_header (void)
1771 {
1772   const guint8 data[] = {
1773     'l',  /* little-endian byte order */
1774     0x01,  /* message type (method call) */
1775     0x00,  /* message flags (none) */
1776     0x01,  /* major protocol version */
1777     0x12, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1778     0x20, 0x20, 0x20, 0x20,  /* message serial */
1779     /* a{yv} of header fields: */
1780     0x24, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1781       0x01,  /* array key (PATH, required for method call messages) */
1782       /* Variant array value: */
1783       0x01,  /* signature length */
1784       'o',  /* one complete type */
1785       0x00,  /* nul terminator */
1786       /* (Variant array value payload) */
1787       0x01, 0x00, 0x00, 0x00,
1788       '/', 0x00, 0x00, 0x00,
1789       0x00, 0x00, 0x00, 0x00,
1790       0x30,  /* array key (MEMBER, required for method call messages; CORRUPTED from 0x03) */
1791       /* Variant array value: */
1792       0x01,  /* signature length */
1793       's',  /* one complete type */
1794       0x00,  /* nul terminator */
1795       /* (Variant array value payload) */
1796       0x03, 0x00, 0x00, 0x00,
1797       'H', 'e', 'y', 0x00,
1798       0x00, 0x00, 0x00, 0x00,
1799       0x08,  /* array key (SIGNATURE) */
1800       /* Variant array value: */
1801       0x01,  /* signature length */
1802       'g',  /* one complete type */
1803       0x00,  /* nul terminator */
1804       /* (Variant array value payload) */
1805       0x02, 's', 's', 0x00,
1806     /* Some arbitrary valid content inside the message body: */
1807     0x03, 0x00, 0x00, 0x00,
1808     'h', 'e', 'y', 0x00,
1809     0x05, 0x00, 0x00, 0x00,
1810     't', 'h', 'e', 'r', 'e', 0x00
1811   };
1812
1813   gsize size = sizeof (data);
1814   GDBusMessage *message = NULL;
1815   GError *local_error = NULL;
1816
1817   g_test_summary ("Test that missing (required) headers prompt an error.");
1818   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3061");
1819
1820   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1821                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1822                                           &local_error);
1823   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1824   g_assert_null (message);
1825
1826   g_clear_error (&local_error);
1827 }
1828
1829 static void
1830 test_message_parse_invalid_header_type (void)
1831 {
1832   const guint8 data[] = {
1833     'l',  /* little-endian byte order */
1834     0x01,  /* message type (method call) */
1835     0x00,  /* message flags (none) */
1836     0x01,  /* major protocol version */
1837     0x12, 0x00, 0x00, 0x00,  /* body length (in bytes) */
1838     0x20, 0x20, 0x20, 0x20,  /* message serial */
1839     /* a{yv} of header fields: */
1840     0x24, 0x00, 0x00, 0x00,  /* array length (in bytes), must be a multiple of 8 */
1841       0x01,  /* array key (PATH, required for method call messages) */
1842       /* Variant array value: */
1843       0x01,  /* signature length */
1844       'o',  /* one complete type */
1845       0x00,  /* nul terminator */
1846       /* (Variant array value payload) */
1847       0x01, 0x00, 0x00, 0x00,
1848       '/', 0x00, 0x00, 0x00,
1849       0x00, 0x00, 0x00, 0x00,
1850       0x03,  /* array key (MEMBER, required for method call messages) */
1851       /* Variant array value: */
1852       0x01,  /* signature length */
1853       't',  /* one complete type; CORRUPTED, MEMBER should be 's' */
1854       0x00,  /* nul terminator */
1855       /* (Padding to 64-bit alignment of 't)' */
1856       0x00, 0x00, 0x00, 0x00,
1857       /* (Variant array value payload) */
1858       'H', 'e', 'y', 0x00,
1859       0x00, 0x00, 0x00, 0x00,
1860       0x08,  /* array key (SIGNATURE) */
1861       /* Variant array value: */
1862       0x01,  /* signature length */
1863       'g',  /* one complete type */
1864       0x00,  /* nul terminator */
1865       /* (Variant array value payload) */
1866       0x02, 's', 's', 0x00,
1867     /* Some arbitrary valid content inside the message body: */
1868     0x03, 0x00, 0x00, 0x00,
1869     'h', 'e', 'y', 0x00,
1870     0x05, 0x00, 0x00, 0x00,
1871     't', 'h', 'e', 'r', 'e', 0x00
1872   };
1873
1874   gsize size = sizeof (data);
1875   GDBusMessage *message = NULL;
1876   GError *local_error = NULL;
1877
1878   g_test_summary ("Test that the type of well-known headers is checked.");
1879   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3061");
1880
1881   message = g_dbus_message_new_from_blob ((guchar *) data, size,
1882                                           G_DBUS_CAPABILITY_FLAGS_NONE,
1883                                           &local_error);
1884   g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1885   g_assert_null (message);
1886
1887   g_clear_error (&local_error);
1888 }
1889
1890 /* ---------------------------------------------------------------------------------------------------- */
1891
1892 int
1893 main (int   argc,
1894       char *argv[])
1895 {
1896   g_setenv ("LC_ALL", "C", TRUE);
1897   setlocale (LC_ALL, "C");
1898
1899   g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1900
1901   g_test_add_func ("/gdbus/message-serialize/basic",
1902                    test_message_serialize_basic);
1903   g_test_add_func ("/gdbus/message-serialize/complex",
1904                    test_message_serialize_complex);
1905   g_test_add_func ("/gdbus/message-serialize/invalid",
1906                    test_message_serialize_invalid);
1907   g_test_add_func ("/gdbus/message-serialize/header-checks",
1908                    test_message_serialize_header_checks);
1909   g_test_add_func ("/gdbus/message-serialize/header-checks/valid",
1910                    test_message_serialize_header_checks_valid);
1911   g_test_add_func ("/gdbus/message-serialize/double-array",
1912                    test_message_serialize_double_array);
1913   g_test_add_func ("/gdbus/message-serialize/empty-structure",
1914                    test_message_serialize_empty_structure);
1915
1916   g_test_add_func ("/gdbus/message-parse/empty-arrays-of-arrays",
1917                    test_message_parse_empty_arrays_of_arrays);
1918   g_test_add_func ("/gdbus/message-parse/non-signature-header",
1919                    test_message_parse_non_signature_header);
1920   g_test_add_func ("/gdbus/message-parse/empty-signature-header",
1921                    test_message_parse_empty_signature_header);
1922   g_test_add_func ("/gdbus/message-parse/multiple-signature-header",
1923                    test_message_parse_multiple_signature_header);
1924   g_test_add_func ("/gdbus/message-parse/over-long-signature-header",
1925                    test_message_parse_over_long_signature_header);
1926   g_test_add_func ("/gdbus/message-parse/deep-header-nesting",
1927                    test_message_parse_deep_header_nesting);
1928   g_test_add_func ("/gdbus/message-parse/deep-body-nesting",
1929                    test_message_parse_deep_body_nesting);
1930   g_test_add_func ("/gdbus/message-parse/truncated",
1931                    test_message_parse_truncated);
1932   g_test_add_func ("/gdbus/message-parse/empty-structure",
1933                    test_message_parse_empty_structure);
1934   g_test_add_func ("/gdbus/message-parse/missing-header",
1935                    test_message_parse_missing_header);
1936   g_test_add_func ("/gdbus/message-parse/invalid-header-type",
1937                    test_message_parse_invalid_header_type);
1938
1939   return g_test_run();
1940 }