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