• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2010 Codethink Limited
3  * Copyright © 2020 William Manley
4  * Copyright © 2022 Endless OS Foundation, LLC
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * See the included COPYING file for more information.
12  *
13  * Author: Ryan Lortie <desrt@desrt.ca>
14  */
15 
16 #include "config.h"
17 
18 #include <glib/gvariant-internal.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <glib.h>
22 
23 #define BASIC "bynqiuxthdsog?"
24 #define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
25 
26 #define INVALIDS "cefjklpwz&@^$"
27 #define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
28 
29 /* see comment in gvariant-serialiser.c about this madness.
30  *
31  * we use this to get testing of non-strictly-aligned GVariant instances
32  * on machines that can tolerate it.  it is necessary to support this
33  * because some systems have malloc() that returns non-8-aligned
34  * pointers.  it is necessary to have special support in the tests
35  * because on most machines malloc() is 8-aligned.
36  */
37 #define ALIGN_BITS (sizeof (struct { char a; union {                       \
38                       guint64 x; void *y; gdouble z; } b; }) - 9)
39 
40 static gboolean
randomly(gdouble prob)41 randomly (gdouble prob)
42 {
43   return g_test_rand_double_range (0, 1) < prob;
44 }
45 
46 /* corecursion */
47 static GVariantType *
48 append_tuple_type_string (GString *, GString *, gboolean, gint);
49 
50 /* append a random GVariantType to a GString
51  * append a description of the type to another GString
52  * return what the type is
53  */
54 static GVariantType *
append_type_string(GString * string,GString * description,gboolean definite,gint depth)55 append_type_string (GString  *string,
56                     GString  *description,
57                     gboolean  definite,
58                     gint      depth)
59 {
60   if (!depth-- || randomly (0.3))
61     {
62       gchar b = BASIC[g_test_rand_int_range (0, N_BASIC - definite)];
63       g_string_append_c (string, b);
64       g_string_append_c (description, b);
65 
66       switch (b)
67         {
68         case 'b':
69           return g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
70         case 'y':
71           return g_variant_type_copy (G_VARIANT_TYPE_BYTE);
72         case 'n':
73           return g_variant_type_copy (G_VARIANT_TYPE_INT16);
74         case 'q':
75           return g_variant_type_copy (G_VARIANT_TYPE_UINT16);
76         case 'i':
77           return g_variant_type_copy (G_VARIANT_TYPE_INT32);
78         case 'u':
79           return g_variant_type_copy (G_VARIANT_TYPE_UINT32);
80         case 'x':
81           return g_variant_type_copy (G_VARIANT_TYPE_INT64);
82         case 't':
83           return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
84         case 'h':
85           return g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
86         case 'd':
87           return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
88         case 's':
89           return g_variant_type_copy (G_VARIANT_TYPE_STRING);
90         case 'o':
91           return g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
92         case 'g':
93           return g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
94         case '?':
95           return g_variant_type_copy (G_VARIANT_TYPE_BASIC);
96         default:
97           g_assert_not_reached ();
98         }
99     }
100   else
101     {
102       GVariantType *result;
103 
104       switch (g_test_rand_int_range (0, definite ? 5 : 7))
105         {
106         case 0:
107           {
108             GVariantType *element;
109 
110             g_string_append_c (string, 'a');
111             g_string_append (description, "a of ");
112             element = append_type_string (string, description,
113                                           definite, depth);
114             result = g_variant_type_new_array (element);
115             g_variant_type_free (element);
116           }
117 
118           g_assert_true (g_variant_type_is_array (result));
119           break;
120 
121         case 1:
122           {
123             GVariantType *element;
124 
125             g_string_append_c (string, 'm');
126             g_string_append (description, "m of ");
127             element = append_type_string (string, description,
128                                           definite, depth);
129             result = g_variant_type_new_maybe (element);
130             g_variant_type_free (element);
131           }
132 
133           g_assert_true (g_variant_type_is_maybe (result));
134           break;
135 
136         case 2:
137           result = append_tuple_type_string (string, description,
138                                              definite, depth);
139 
140           g_assert_true (g_variant_type_is_tuple (result));
141           break;
142 
143         case 3:
144           {
145             GVariantType *key, *value;
146 
147             g_string_append_c (string, '{');
148             g_string_append (description, "e of [");
149             key = append_type_string (string, description, definite, 0);
150             g_string_append (description, ", ");
151             value = append_type_string (string, description, definite, depth);
152             g_string_append_c (description, ']');
153             g_string_append_c (string, '}');
154             result = g_variant_type_new_dict_entry (key, value);
155             g_variant_type_free (key);
156             g_variant_type_free (value);
157           }
158 
159           g_assert_true (g_variant_type_is_dict_entry (result));
160           break;
161 
162         case 4:
163           g_string_append_c (string, 'v');
164           g_string_append_c (description, 'V');
165           result = g_variant_type_copy (G_VARIANT_TYPE_VARIANT);
166           g_assert_true (g_variant_type_equal (result, G_VARIANT_TYPE_VARIANT));
167           break;
168 
169         case 5:
170           g_string_append_c (string, '*');
171           g_string_append_c (description, 'S');
172           result = g_variant_type_copy (G_VARIANT_TYPE_ANY);
173           g_assert_true (g_variant_type_equal (result, G_VARIANT_TYPE_ANY));
174           break;
175 
176         case 6:
177           g_string_append_c (string, 'r');
178           g_string_append_c (description, 'R');
179           result = g_variant_type_copy (G_VARIANT_TYPE_TUPLE);
180           g_assert_true (g_variant_type_is_tuple (result));
181           break;
182 
183         default:
184           g_assert_not_reached ();
185         }
186 
187       return result;
188     }
189 }
190 
191 static GVariantType *
append_tuple_type_string(GString * string,GString * description,gboolean definite,gint depth)192 append_tuple_type_string (GString  *string,
193                           GString  *description,
194                           gboolean  definite,
195                           gint      depth)
196 {
197   GVariantType *result, *other_result;
198   GVariantType **types;
199   gsize i, size;
200 
201   g_string_append_c (string, '(');
202   g_string_append (description, "t of [");
203 
204   size = g_test_rand_int_range (0, 20);
205   types = g_new (GVariantType *, size + 1);
206 
207   for (i = 0; i < size; i++)
208     {
209       types[i] = append_type_string (string, description, definite, depth);
210 
211       if (i < size - 1)
212         g_string_append (description, ", ");
213     }
214 
215   types[i] = NULL;
216 
217   g_string_append_c (description, ']');
218   g_string_append_c (string, ')');
219 
220   result = g_variant_type_new_tuple ((gpointer) types, size);
221   other_result = g_variant_type_new_tuple ((gpointer) types, -1);
222   g_assert_true (g_variant_type_equal (result, other_result));
223   g_variant_type_free (other_result);
224   for (i = 0; i < size; i++)
225     g_variant_type_free (types[i]);
226   g_free (types);
227 
228   return result;
229 }
230 
231 /* given a valid type string, make it invalid */
232 static gchar *
invalid_mutation(const gchar * type_string)233 invalid_mutation (const gchar *type_string)
234 {
235   gboolean have_parens, have_braces;
236 
237   /* it's valid, so '(' implies ')' and same for '{' and '}' */
238   have_parens = strchr (type_string, '(') != NULL;
239   have_braces = strchr (type_string, '{') != NULL;
240 
241   if (have_parens && have_braces && randomly (0.3))
242     {
243       /* swap a paren and a brace */
244       gchar *pp, *bp;
245       gint np, nb;
246       gchar p, b;
247       gchar *new;
248 
249       new = g_strdup (type_string);
250 
251       if (randomly (0.5))
252         p = '(', b = '{';
253       else
254         p = ')', b = '}';
255 
256       np = nb = 0;
257       pp = bp = new - 1;
258 
259       /* count number of parens/braces */
260       while ((pp = strchr (pp + 1, p))) np++;
261       while ((bp = strchr (bp + 1, b))) nb++;
262 
263       /* randomly pick one of each */
264       np = g_test_rand_int_range (0, np) + 1;
265       nb = g_test_rand_int_range (0, nb) + 1;
266 
267       /* find it */
268       pp = bp = new - 1;
269       while (np--) pp = strchr (pp + 1, p);
270       while (nb--) bp = strchr (bp + 1, b);
271 
272       /* swap */
273       g_assert_true (*bp == b && *pp == p);
274       *bp = p;
275       *pp = b;
276 
277       return new;
278     }
279 
280   if ((have_parens || have_braces) && randomly (0.3))
281     {
282       /* drop a paren/brace */
283       gchar *new;
284       gchar *pp;
285       gint np;
286       gchar p;
287 
288       if (have_parens)
289         if (randomly (0.5)) p = '('; else p = ')';
290       else
291         if (randomly (0.5)) p = '{'; else p = '}';
292 
293       new = g_strdup (type_string);
294 
295       np = 0;
296       pp = new - 1;
297       while ((pp = strchr (pp + 1, p))) np++;
298       np = g_test_rand_int_range (0, np) + 1;
299       pp = new - 1;
300       while (np--) pp = strchr (pp + 1, p);
301       g_assert_cmpint (*pp, ==, p);
302 
303       while (*pp)
304         {
305           *pp = *(pp + 1);
306           pp++;
307         }
308 
309       return new;
310     }
311 
312   /* else, perform a random mutation at a random point */
313   {
314     gint length, n;
315     gchar *new;
316     gchar p;
317 
318     if (randomly (0.3))
319       {
320         /* insert a paren/brace */
321         if (randomly (0.5))
322           if (randomly (0.5)) p = '('; else p = ')';
323         else
324           if (randomly (0.5)) p = '{'; else p = '}';
325       }
326     else if (randomly (0.5))
327       {
328         /* insert junk */
329         p = INVALIDS[g_test_rand_int_range (0, N_INVALIDS)];
330       }
331     else
332       {
333         /* truncate */
334         p = '\0';
335       }
336 
337 
338     length = strlen (type_string);
339     new = g_malloc (length + 2);
340     n = g_test_rand_int_range (0, length);
341     memcpy (new, type_string, n);
342     new[n] = p;
343     memcpy (new + n + 1, type_string + n, length - n);
344     new[length + 1] = '\0';
345 
346     return new;
347   }
348 }
349 
350 /* describe a type using the same language as is generated
351  * while generating the type with append_type_string
352  */
353 static gchar *
describe_type(const GVariantType * type)354 describe_type (const GVariantType *type)
355 {
356   gchar *result;
357 
358   if (g_variant_type_is_container (type))
359     {
360       g_assert_false (g_variant_type_is_basic (type));
361 
362       if (g_variant_type_is_array (type))
363         {
364           gchar *subtype = describe_type (g_variant_type_element (type));
365           result = g_strdup_printf ("a of %s", subtype);
366           g_free (subtype);
367         }
368       else if (g_variant_type_is_maybe (type))
369         {
370           gchar *subtype = describe_type (g_variant_type_element (type));
371           result = g_strdup_printf ("m of %s", subtype);
372           g_free (subtype);
373         }
374       else if (g_variant_type_is_tuple (type))
375         {
376           if (!g_variant_type_equal (type, G_VARIANT_TYPE_TUPLE))
377             {
378               const GVariantType *sub;
379               GString *string;
380               gsize i, length;
381 
382               string = g_string_new ("t of [");
383 
384               length = g_variant_type_n_items (type);
385               sub = g_variant_type_first (type);
386               for (i = 0; i < length; i++)
387                 {
388                   gchar *subtype = describe_type (sub);
389                   g_string_append (string, subtype);
390                   g_free (subtype);
391 
392                   if ((sub = g_variant_type_next (sub)))
393                     g_string_append (string, ", ");
394                 }
395               g_assert_null (sub);
396               g_string_append_c (string, ']');
397 
398               result = g_string_free (string, FALSE);
399             }
400           else
401             result = g_strdup ("R");
402         }
403       else if (g_variant_type_is_dict_entry (type))
404         {
405           gchar *key, *value, *key2, *value2;
406 
407           key = describe_type (g_variant_type_key (type));
408           value = describe_type (g_variant_type_value (type));
409           key2 = describe_type (g_variant_type_first (type));
410           value2 = describe_type (
411             g_variant_type_next (g_variant_type_first (type)));
412           g_assert_null (g_variant_type_next (g_variant_type_next (
413             g_variant_type_first (type))));
414           g_assert_cmpstr (key, ==, key2);
415           g_assert_cmpstr (value, ==, value2);
416           result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
417           g_free (key2);
418           g_free (value2);
419           g_free (key);
420           g_free (value);
421         }
422       else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
423         {
424           result = g_strdup ("V");
425         }
426       else
427         g_assert_not_reached ();
428     }
429   else
430     {
431       if (g_variant_type_is_definite (type))
432         {
433           g_assert_true (g_variant_type_is_basic (type));
434 
435           if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
436             result = g_strdup ("b");
437           else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
438             result = g_strdup ("y");
439           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
440             result = g_strdup ("n");
441           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
442             result = g_strdup ("q");
443           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
444             result = g_strdup ("i");
445           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
446             result = g_strdup ("u");
447           else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
448             result = g_strdup ("x");
449           else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
450             result = g_strdup ("t");
451           else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
452             result = g_strdup ("h");
453           else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
454             result = g_strdup ("d");
455           else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
456             result = g_strdup ("s");
457           else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
458             result = g_strdup ("o");
459           else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
460             result = g_strdup ("g");
461           else
462             g_assert_not_reached ();
463         }
464       else
465         {
466           if (g_variant_type_equal (type, G_VARIANT_TYPE_ANY))
467             {
468               result = g_strdup ("S");
469             }
470           else if (g_variant_type_equal (type, G_VARIANT_TYPE_BASIC))
471             {
472               result = g_strdup ("?");
473             }
474           else
475             g_assert_not_reached ();
476         }
477     }
478 
479   return result;
480 }
481 
482 /* given a type string, replace one of the indefinite type characters in
483  * it with a matching type (possibly the same type).
484  */
485 static gchar *
generate_subtype(const gchar * type_string)486 generate_subtype (const gchar *type_string)
487 {
488   GVariantType *replacement;
489   GString *result, *junk;
490   gint l;
491   gsize length, n = 0;
492 
493   result = g_string_new (NULL);
494   junk = g_string_new (NULL);
495 
496   /* count the number of indefinite type characters */
497   for (length = 0; type_string[length]; length++)
498     n += type_string[length] == 'r' ||
499          type_string[length] == '?' ||
500          type_string[length] == '*';
501   /* length now is strlen (type_string) */
502 
503   /* pick one at random to replace */
504   n = g_test_rand_int_range (0, n) + 1;
505 
506   /* find it */
507   l = -1;
508   while (n--) l += strcspn (type_string + l + 1, "r?*") + 1;
509   g_assert_true (type_string[l] == 'r' ||
510                  type_string[l] == '?' ||
511                  type_string[l] == '*');
512 
513   /* store up to that point in a GString */
514   g_string_append_len (result, type_string, l);
515 
516   /* then store the replacement in the GString */
517   if (type_string[l] == 'r')
518     replacement = append_tuple_type_string (result, junk, FALSE, 3);
519 
520   else if (type_string[l] == '?')
521     replacement = append_type_string (result, junk, FALSE, 0);
522 
523   else if (type_string[l] == '*')
524     replacement = append_type_string (result, junk, FALSE, 3);
525 
526   else
527     g_assert_not_reached ();
528 
529   /* ensure the replacement has the proper type */
530   g_assert_true (g_variant_type_is_subtype_of (replacement,
531                                                (gpointer) &type_string[l]));
532 
533   /* store the rest from the original type string */
534   g_string_append (result, type_string + l + 1);
535 
536   g_variant_type_free (replacement);
537   g_string_free (junk, TRUE);
538 
539   return g_string_free (result, FALSE);
540 }
541 
542 struct typestack
543 {
544   const GVariantType *type;
545   struct typestack *parent;
546 };
547 
548 /* given an indefinite type string, replace one of the indefinite
549  * characters in it with a matching type and ensure that the result is a
550  * subtype of the original.  repeat.
551  */
552 static void
subtype_check(const gchar * type_string,struct typestack * parent_ts)553 subtype_check (const gchar      *type_string,
554                struct typestack *parent_ts)
555 {
556   struct typestack ts, *node;
557   gchar *subtype;
558   gint depth = 0;
559 
560   subtype = generate_subtype (type_string);
561 
562   ts.type = G_VARIANT_TYPE (subtype);
563   ts.parent = parent_ts;
564 
565   for (node = &ts; node; node = node->parent)
566     {
567       /* this type should be a subtype of each parent type */
568       g_assert_true (g_variant_type_is_subtype_of (ts.type, node->type));
569 
570       /* it should only be a supertype when it is exactly equal */
571       g_assert_true (g_variant_type_is_subtype_of (node->type, ts.type) ==
572                      g_variant_type_equal (ts.type, node->type));
573 
574       depth++;
575     }
576 
577   if (!g_variant_type_is_definite (ts.type) && depth < 5)
578     {
579       /* the type is still indefinite and we haven't repeated too many
580        * times.  go once more.
581        */
582 
583       subtype_check (subtype, &ts);
584     }
585 
586   g_free (subtype);
587 }
588 
589 static void
test_gvarianttype(void)590 test_gvarianttype (void)
591 {
592   gsize i;
593 
594   for (i = 0; i < 2000; i++)
595     {
596       GString *type_string, *description;
597       GVariantType *type, *other_type;
598       const GVariantType *ctype;
599       gchar *invalid;
600       gchar *desc;
601 
602       type_string = g_string_new (NULL);
603       description = g_string_new (NULL);
604 
605       /* generate a random type, its type string and a description
606        *
607        * exercises type constructor functions and g_variant_type_copy()
608        */
609       type = append_type_string (type_string, description, FALSE, 6);
610 
611       /* convert the type string to a type and ensure that it is equal
612        * to the one produced with the type constructor routines
613        */
614       ctype = G_VARIANT_TYPE (type_string->str);
615       g_assert_true (g_variant_type_equal (ctype, type));
616       g_assert_cmpuint (g_variant_type_hash (ctype), ==, g_variant_type_hash (type));
617       g_assert_true (g_variant_type_is_subtype_of (ctype, type));
618       g_assert_true (g_variant_type_is_subtype_of (type, ctype));
619 
620       /* check if the type is indefinite */
621       if (!g_variant_type_is_definite (type))
622         {
623           struct typestack ts = { type, NULL };
624 
625           /* if it is indefinite, then replace one of the indefinite
626            * characters with a matching type and ensure that the result
627            * is a subtype of the original type.  repeat.
628            */
629           subtype_check (type_string->str, &ts);
630         }
631       else
632         /* ensure that no indefinite characters appear */
633         g_assert_cmpint (strcspn (type_string->str, "r?*"), ==, type_string->len);
634 
635 
636       /* describe the type.
637        *
638        * exercises the type iterator interface
639        */
640       desc = describe_type (type);
641 
642       /* make sure the description matches */
643       g_assert_cmpstr (desc, ==, description->str);
644       g_free (desc);
645 
646       /* make an invalid mutation to the type and make sure the type
647        * validation routines catch it */
648       invalid = invalid_mutation (type_string->str);
649       g_assert_true (g_variant_type_string_is_valid (type_string->str));
650       g_assert_false (g_variant_type_string_is_valid (invalid));
651       g_free (invalid);
652 
653       /* concatenate another type to the type string and ensure that
654        * the result is recognised as being invalid
655        */
656       other_type = append_type_string (type_string, description, FALSE, 2);
657 
658       g_string_free (description, TRUE);
659       g_string_free (type_string, TRUE);
660       g_variant_type_free (other_type);
661       g_variant_type_free (type);
662     }
663 }
664 
665 /* Test that scanning a deeply recursive type string doesn’t exhaust our
666  * stack space (which it would if the type string scanner was recursive). */
667 static void
test_gvarianttype_string_scan_recursion_tuple(void)668 test_gvarianttype_string_scan_recursion_tuple (void)
669 {
670   gchar *type_string = NULL;
671   gsize type_string_len = 1000001;  /* not including nul terminator */
672   gsize i;
673 
674   /* Build a long type string of ‘((…u…))’. */
675   type_string = g_new0 (gchar, type_string_len + 1);
676   for (i = 0; i < type_string_len; i++)
677     {
678       if (i < type_string_len / 2)
679         type_string[i] = '(';
680       else if (i == type_string_len / 2)
681         type_string[i] = 'u';
682       else
683         type_string[i] = ')';
684     }
685 
686   /* Goes (way) over allowed recursion limit. */
687   g_assert_false (g_variant_type_string_is_valid (type_string));
688 
689   g_free (type_string);
690 }
691 
692 /* Same as above, except with an array rather than a tuple. */
693 static void
test_gvarianttype_string_scan_recursion_array(void)694 test_gvarianttype_string_scan_recursion_array (void)
695 {
696   gchar *type_string = NULL;
697   gsize type_string_len = 1000001;  /* not including nul terminator */
698   gsize i;
699 
700   /* Build a long type string of ‘aaa…aau’. */
701   type_string = g_new0 (gchar, type_string_len + 1);
702   for (i = 0; i < type_string_len; i++)
703     {
704       if (i < type_string_len - 1)
705         type_string[i] = 'a';
706       else
707         type_string[i] = 'u';
708     }
709 
710   /* Goes (way) over allowed recursion limit. */
711   g_assert_false (g_variant_type_string_is_valid (type_string));
712 
713   g_free (type_string);
714 }
715 
716 #define ALIGNED(x, y)   (((x + (y - 1)) / y) * y)
717 
718 /* do our own calculation of the fixed_size and alignment of a type
719  * using a simple algorithm to make sure the "fancy" one in the
720  * implementation is correct.
721  */
722 static void
calculate_type_info(const GVariantType * type,gsize * fixed_size,guint * alignment)723 calculate_type_info (const GVariantType *type,
724                      gsize              *fixed_size,
725                      guint              *alignment)
726 {
727   if (g_variant_type_is_array (type) ||
728       g_variant_type_is_maybe (type))
729     {
730       calculate_type_info (g_variant_type_element (type), NULL, alignment);
731 
732       if (fixed_size)
733         *fixed_size = 0;
734     }
735   else if (g_variant_type_is_tuple (type) ||
736            g_variant_type_is_dict_entry (type))
737     {
738       if (g_variant_type_n_items (type))
739         {
740           const GVariantType *sub;
741           gboolean variable;
742           gsize size;
743           guint al;
744 
745           variable = FALSE;
746           size = 0;
747           al = 0;
748 
749           sub = g_variant_type_first (type);
750           do
751             {
752               gsize this_fs;
753               guint this_al;
754 
755               calculate_type_info (sub, &this_fs, &this_al);
756 
757               al = MAX (al, this_al);
758 
759               if (!this_fs)
760                 {
761                   variable = TRUE;
762                   size = 0;
763                 }
764 
765               if (!variable)
766                 {
767                   size = ALIGNED (size, this_al);
768                   size += this_fs;
769                 }
770             }
771           while ((sub = g_variant_type_next (sub)));
772 
773           size = ALIGNED (size, al);
774 
775           if (alignment)
776             *alignment = al;
777 
778           if (fixed_size)
779             *fixed_size = size;
780         }
781       else
782         {
783           if (fixed_size)
784             *fixed_size = 1;
785 
786           if (alignment)
787             *alignment = 1;
788         }
789     }
790   else
791     {
792       gint fs, al;
793 
794       if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN) ||
795           g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
796         {
797           al = fs = 1;
798         }
799 
800       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16) ||
801                g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
802         {
803           al = fs = 2;
804         }
805 
806       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32) ||
807                g_variant_type_equal (type, G_VARIANT_TYPE_UINT32) ||
808                g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
809         {
810           al = fs = 4;
811         }
812 
813       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64) ||
814                g_variant_type_equal (type, G_VARIANT_TYPE_UINT64) ||
815                g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
816         {
817           al = fs = 8;
818         }
819       else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING) ||
820                g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH) ||
821                g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
822         {
823           al = 1;
824           fs = 0;
825         }
826       else if (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
827         {
828           al = 8;
829           fs = 0;
830         }
831       else
832         g_assert_not_reached ();
833 
834       if (fixed_size)
835         *fixed_size = fs;
836 
837       if (alignment)
838         *alignment = al;
839     }
840 }
841 
842 /* same as the describe_type() function above, but iterates over
843  * typeinfo instead of types.
844  */
845 static gchar *
describe_info(GVariantTypeInfo * info)846 describe_info (GVariantTypeInfo *info)
847 {
848   gchar *result;
849 
850   switch (g_variant_type_info_get_type_char (info))
851     {
852     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
853       {
854         gchar *element;
855 
856         element = describe_info (g_variant_type_info_element (info));
857         result = g_strdup_printf ("m of %s", element);
858         g_free (element);
859       }
860       break;
861 
862     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
863       {
864         gchar *element;
865 
866         element = describe_info (g_variant_type_info_element (info));
867         result = g_strdup_printf ("a of %s", element);
868         g_free (element);
869       }
870       break;
871 
872     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
873       {
874         const gchar *sep = "";
875         GString *string;
876         gsize i, length;
877 
878         string = g_string_new ("t of [");
879         length = g_variant_type_info_n_members (info);
880 
881         for (i = 0; i < length; i++)
882           {
883             const GVariantMemberInfo *minfo;
884             gchar *subtype;
885 
886             g_string_append (string, sep);
887             sep = ", ";
888 
889             minfo = g_variant_type_info_member_info (info, i);
890             subtype = describe_info (minfo->type_info);
891             g_string_append (string, subtype);
892             g_free (subtype);
893           }
894 
895         g_string_append_c (string, ']');
896 
897         result = g_string_free (string, FALSE);
898       }
899       break;
900 
901     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
902       {
903         const GVariantMemberInfo *keyinfo, *valueinfo;
904         gchar *key, *value;
905 
906         g_assert_cmpint (g_variant_type_info_n_members (info), ==, 2);
907         keyinfo = g_variant_type_info_member_info (info, 0);
908         valueinfo = g_variant_type_info_member_info (info, 1);
909         key = describe_info (keyinfo->type_info);
910         value = describe_info (valueinfo->type_info);
911         result = g_strjoin ("", "e of [", key, ", ", value, "]", NULL);
912         g_free (key);
913         g_free (value);
914       }
915       break;
916 
917     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
918       result = g_strdup ("V");
919       break;
920 
921     default:
922       result = g_strdup (g_variant_type_info_get_type_string (info));
923       g_assert_cmpint (strlen (result), ==, 1);
924       break;
925     }
926 
927   return result;
928 }
929 
930 /* check that the O(1) method of calculating offsets meshes with the
931  * results of simple iteration.
932  */
933 static void
check_offsets(GVariantTypeInfo * info,const GVariantType * type)934 check_offsets (GVariantTypeInfo   *info,
935                const GVariantType *type)
936 {
937   gsize flavour, length;
938 
939   length = g_variant_type_info_n_members (info);
940   g_assert_cmpuint (length, ==, g_variant_type_n_items (type));
941 
942   /* the 'flavour' is the low order bits of the ending point of
943    * variable-size items in the tuple.  this lets us test that the type
944    * info is correct for various starting alignments.
945    */
946   for (flavour = 0; flavour < 8; flavour++)
947     {
948       const GVariantType *subtype;
949       gsize last_offset_index;
950       gsize last_offset;
951       gsize position;
952       gsize i;
953 
954       subtype = g_variant_type_first (type);
955       last_offset_index = -1;
956       last_offset = 0;
957       position = 0;
958 
959       /* go through the tuple, keeping track of our position */
960       for (i = 0; i < length; i++)
961         {
962           gsize fixed_size;
963           guint alignment;
964 
965           calculate_type_info (subtype, &fixed_size, &alignment);
966 
967           position = ALIGNED (position, alignment);
968 
969           /* compare our current aligned position (ie: the start of this
970            * item) to the start offset that would be calculated if we
971            * used the type info
972            */
973           {
974             const GVariantMemberInfo *member;
975             gsize start;
976 
977             member = g_variant_type_info_member_info (info, i);
978             g_assert_cmpint (member->i, ==, last_offset_index);
979 
980             /* do the calculation using the typeinfo */
981             start = last_offset;
982             start += member->a;
983             start &= member->b;
984             start |= member->c;
985 
986             /* did we reach the same spot? */
987             g_assert_cmpint (start, ==, position);
988           }
989 
990           if (fixed_size)
991             {
992               /* fixed size.  add that size. */
993               position += fixed_size;
994             }
995           else
996             {
997               /* variable size.  do the flavouring. */
998               while ((position & 0x7) != flavour)
999                 position++;
1000 
1001               /* and store the offset, just like it would be in the
1002                * serialised data.
1003                */
1004               last_offset = position;
1005               last_offset_index++;
1006             }
1007 
1008           /* next type */
1009           subtype = g_variant_type_next (subtype);
1010         }
1011 
1012       /* make sure we used up exactly all the types */
1013       g_assert_null (subtype);
1014     }
1015 }
1016 
1017 static void
test_gvarianttypeinfo(void)1018 test_gvarianttypeinfo (void)
1019 {
1020   gsize i;
1021 
1022   for (i = 0; i < 2000; i++)
1023     {
1024       GString *type_string, *description;
1025       gsize fixed_size1, fixed_size2;
1026       guint alignment1, alignment2;
1027       GVariantTypeInfo *info;
1028       GVariantType *type;
1029       gchar *desc;
1030 
1031       type_string = g_string_new (NULL);
1032       description = g_string_new (NULL);
1033 
1034       /* random type */
1035       type = append_type_string (type_string, description, TRUE, 6);
1036 
1037       /* create a typeinfo for it */
1038       info = g_variant_type_info_get (type);
1039 
1040       /* make sure the typeinfo has the right type string */
1041       g_assert_cmpstr (g_variant_type_info_get_type_string (info), ==,
1042                        type_string->str);
1043 
1044       /* calculate the alignment and fixed size, compare to the
1045        * typeinfo's calculations
1046        */
1047       calculate_type_info (type, &fixed_size1, &alignment1);
1048       g_variant_type_info_query (info, &alignment2, &fixed_size2);
1049       g_assert_cmpint (fixed_size1, ==, fixed_size2);
1050       g_assert_cmpint (alignment1, ==, alignment2 + 1);
1051 
1052       /* test the iteration functions over typeinfo structures by
1053        * "describing" the typeinfo and verifying equality.
1054        */
1055       desc = describe_info (info);
1056       g_assert_cmpstr (desc, ==, description->str);
1057 
1058       /* do extra checks for containers */
1059       if (g_variant_type_is_array (type) ||
1060           g_variant_type_is_maybe (type))
1061         {
1062           const GVariantType *element;
1063           gsize efs1, efs2;
1064           guint ea1, ea2;
1065 
1066           element = g_variant_type_element (type);
1067           calculate_type_info (element, &efs1, &ea1);
1068           g_variant_type_info_query_element (info, &ea2, &efs2);
1069           g_assert_cmpint (efs1, ==, efs2);
1070           g_assert_cmpint (ea1, ==, ea2 + 1);
1071 
1072           g_assert_cmpint (ea1, ==, alignment1);
1073           g_assert_cmpint (0, ==, fixed_size1);
1074         }
1075       else if (g_variant_type_is_tuple (type) ||
1076                g_variant_type_is_dict_entry (type))
1077         {
1078           /* make sure the "magic constants" are working */
1079           check_offsets (info, type);
1080         }
1081 
1082       g_string_free (type_string, TRUE);
1083       g_string_free (description, TRUE);
1084       g_variant_type_info_unref (info);
1085       g_variant_type_free (type);
1086       g_free (desc);
1087     }
1088 
1089   g_variant_type_info_assert_no_infos ();
1090 }
1091 
1092 #define MAX_FIXED_MULTIPLIER    256
1093 #define MAX_INSTANCE_SIZE       1024
1094 #define MAX_ARRAY_CHILDREN      128
1095 #define MAX_TUPLE_CHILDREN      128
1096 
1097 /* this function generates a random type such that all characteristics
1098  * that are "interesting" to the serialiser are tested.
1099  *
1100  * this basically means:
1101  *   - test different alignments
1102  *   - test variable sized items and fixed sized items
1103  *   - test different fixed sizes
1104  */
1105 static gchar *
random_type_string(void)1106 random_type_string (void)
1107 {
1108   const guchar base_types[] = "ynix";
1109   guchar base_type;
1110 
1111   base_type = base_types[g_test_rand_int_range (0, 4)];
1112 
1113   if (g_test_rand_bit ())
1114     /* construct a fixed-sized type */
1115     {
1116       char type_string[MAX_FIXED_MULTIPLIER];
1117       guint multiplier;
1118       gsize i = 0;
1119 
1120       multiplier = g_test_rand_int_range (1, sizeof type_string - 1);
1121 
1122       type_string[i++] = '(';
1123       while (multiplier--)
1124         type_string[i++] = base_type;
1125       type_string[i++] = ')';
1126 
1127       return g_strndup (type_string, i);
1128     }
1129   else
1130     /* construct a variable-sized type */
1131     {
1132       char type_string[2] = { 'a', base_type };
1133 
1134       return g_strndup (type_string, 2);
1135     }
1136 }
1137 
1138 typedef struct
1139 {
1140   GVariantTypeInfo *type_info;
1141   guint alignment;
1142   gsize size;
1143   gboolean is_fixed_sized;
1144 
1145   guint32 seed;
1146 
1147 #define INSTANCE_MAGIC    1287582829
1148   guint magic;
1149 } RandomInstance;
1150 
1151 static RandomInstance *
random_instance(GVariantTypeInfo * type_info)1152 random_instance (GVariantTypeInfo *type_info)
1153 {
1154   RandomInstance *instance;
1155 
1156   instance = g_slice_new (RandomInstance);
1157 
1158   if (type_info == NULL)
1159     {
1160       gchar *str = random_type_string ();
1161       instance->type_info = g_variant_type_info_get (G_VARIANT_TYPE (str));
1162       g_free (str);
1163     }
1164   else
1165     instance->type_info = g_variant_type_info_ref (type_info);
1166 
1167   instance->seed = g_test_rand_int ();
1168 
1169   g_variant_type_info_query (instance->type_info,
1170                              &instance->alignment,
1171                              &instance->size);
1172 
1173   instance->is_fixed_sized = instance->size != 0;
1174 
1175   if (!instance->is_fixed_sized)
1176     instance->size = g_test_rand_int_range (0, MAX_INSTANCE_SIZE);
1177 
1178   instance->magic = INSTANCE_MAGIC;
1179 
1180   return instance;
1181 }
1182 
1183 static void
random_instance_free(RandomInstance * instance)1184 random_instance_free (RandomInstance *instance)
1185 {
1186   g_variant_type_info_unref (instance->type_info);
1187   g_slice_free (RandomInstance, instance);
1188 }
1189 
1190 static void
append_instance_size(RandomInstance * instance,gsize * offset)1191 append_instance_size (RandomInstance *instance,
1192                       gsize          *offset)
1193 {
1194   *offset += (-*offset) & instance->alignment;
1195   *offset += instance->size;
1196 }
1197 
1198 static void
random_instance_write(RandomInstance * instance,guchar * buffer)1199 random_instance_write (RandomInstance *instance,
1200                        guchar         *buffer)
1201 {
1202   GRand *rand;
1203   gsize i;
1204 
1205   g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
1206 
1207   rand = g_rand_new_with_seed (instance->seed);
1208   for (i = 0; i < instance->size; i++)
1209     buffer[i] = g_rand_int (rand);
1210   g_rand_free (rand);
1211 }
1212 
1213 static void
append_instance_data(RandomInstance * instance,guchar ** buffer)1214 append_instance_data (RandomInstance  *instance,
1215                       guchar         **buffer)
1216 {
1217   while (((gsize) *buffer) & instance->alignment)
1218     *(*buffer)++ = '\0';
1219 
1220   random_instance_write (instance, *buffer);
1221   *buffer += instance->size;
1222 }
1223 
1224 static gboolean
random_instance_assert(RandomInstance * instance,guchar * buffer,gsize size)1225 random_instance_assert (RandomInstance *instance,
1226                         guchar         *buffer,
1227                         gsize           size)
1228 {
1229   GRand *rand;
1230   gsize i;
1231 
1232   g_assert_true (size == 0 || buffer != NULL);
1233   g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
1234   g_assert_cmpint (size, ==, instance->size);
1235 
1236   rand = g_rand_new_with_seed (instance->seed);
1237   for (i = 0; i < instance->size; i++)
1238     {
1239       guchar byte = g_rand_int (rand);
1240 
1241       g_assert_cmpuint (buffer[i], ==, byte);
1242     }
1243   g_rand_free (rand);
1244 
1245   return i == instance->size;
1246 }
1247 
1248 static gboolean
random_instance_check(RandomInstance * instance,guchar * buffer,gsize size)1249 random_instance_check (RandomInstance *instance,
1250                        guchar         *buffer,
1251                        gsize           size)
1252 {
1253   GRand *rand;
1254   gsize i;
1255 
1256   g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
1257 
1258   if (size != instance->size)
1259     return FALSE;
1260 
1261   rand = g_rand_new_with_seed (instance->seed);
1262   for (i = 0; i < instance->size; i++)
1263     if (buffer[i] != (guchar) g_rand_int (rand))
1264       break;
1265   g_rand_free (rand);
1266 
1267   return i == instance->size;
1268 }
1269 
1270 static void
random_instance_filler(GVariantSerialised * serialised,gpointer data)1271 random_instance_filler (GVariantSerialised *serialised,
1272                         gpointer            data)
1273 {
1274   RandomInstance *instance = data;
1275 
1276   g_assert_cmpuint (instance->magic, ==, INSTANCE_MAGIC);
1277 
1278   if (serialised->type_info == NULL)
1279     serialised->type_info = instance->type_info;
1280 
1281   if (serialised->size == 0)
1282     serialised->size = instance->size;
1283 
1284   serialised->depth = 0;
1285   serialised->ordered_offsets_up_to = 0;
1286   serialised->checked_offsets_up_to = 0;
1287 
1288   g_assert_true (serialised->type_info == instance->type_info);
1289   g_assert_cmpuint (serialised->size, ==, instance->size);
1290 
1291   if (serialised->data)
1292     random_instance_write (instance, serialised->data);
1293 }
1294 
1295 static gsize
calculate_offset_size(gsize body_size,gsize n_offsets)1296 calculate_offset_size (gsize body_size,
1297                        gsize n_offsets)
1298 {
1299   if (body_size == 0)
1300     return 0;
1301 
1302   if (body_size + n_offsets <= G_MAXUINT8)
1303     return 1;
1304 
1305   if (body_size + 2 * n_offsets <= G_MAXUINT16)
1306     return 2;
1307 
1308   if (body_size + 4 * n_offsets <= G_MAXUINT32)
1309     return 4;
1310 
1311   /* the test case won't generate anything bigger */
1312   g_assert_not_reached ();
1313 }
1314 
1315 static gpointer
flavoured_malloc(gsize size,gsize flavour)1316 flavoured_malloc (gsize size, gsize flavour)
1317 {
1318   g_assert_cmpuint (flavour, <, 8);
1319 
1320   if (size == 0)
1321     return NULL;
1322 
1323   return ((gchar *) g_malloc (size + flavour)) + flavour;
1324 }
1325 
1326 static void
flavoured_free(gpointer data,gsize flavour)1327 flavoured_free (gpointer data,
1328                 gsize flavour)
1329 {
1330   if (!data)
1331     return;
1332   g_free (((gchar *) data) - flavour);
1333 }
1334 
1335 static gpointer
align_malloc(gsize size)1336 align_malloc (gsize size)
1337 {
1338   gpointer mem;
1339 
1340 #ifdef HAVE_POSIX_MEMALIGN
1341   if (posix_memalign (&mem, 8, size))
1342     g_error ("posix_memalign failed");
1343 #else
1344   /* NOTE: there may be platforms that lack posix_memalign() and also
1345    * have malloc() that returns non-8-aligned.  if so, we need to try
1346    * harder here.
1347    */
1348   mem = malloc (size);
1349 #endif
1350 
1351   return mem;
1352 }
1353 
1354 static void
align_free(gpointer mem)1355 align_free (gpointer mem)
1356 {
1357   free (mem);
1358 }
1359 
1360 static void
append_offset(guchar ** offset_ptr,gsize offset,guint offset_size)1361 append_offset (guchar **offset_ptr,
1362                gsize    offset,
1363                guint    offset_size)
1364 {
1365   union
1366   {
1367     guchar bytes[sizeof (gsize)];
1368     gsize integer;
1369   } tmpvalue;
1370 
1371   tmpvalue.integer = GSIZE_TO_LE (offset);
1372   memcpy (*offset_ptr, tmpvalue.bytes, offset_size);
1373   *offset_ptr += offset_size;
1374 }
1375 
1376 static void
prepend_offset(guchar ** offset_ptr,gsize offset,guint offset_size)1377 prepend_offset (guchar **offset_ptr,
1378                 gsize    offset,
1379                 guint    offset_size)
1380 {
1381   union
1382   {
1383     guchar bytes[sizeof (gsize)];
1384     gsize integer;
1385   } tmpvalue;
1386 
1387   *offset_ptr -= offset_size;
1388   tmpvalue.integer = GSIZE_TO_LE (offset);
1389   memcpy (*offset_ptr, tmpvalue.bytes, offset_size);
1390 }
1391 
1392 static void
test_maybe(void)1393 test_maybe (void)
1394 {
1395   GVariantTypeInfo *type_info;
1396   RandomInstance *instance;
1397   gsize needed_size;
1398   guchar *data;
1399 
1400   instance = random_instance (NULL);
1401 
1402   {
1403     const gchar *element;
1404     gchar *tmp;
1405 
1406     element = g_variant_type_info_get_type_string (instance->type_info);
1407     tmp = g_strdup_printf ("m%s", element);
1408     type_info = g_variant_type_info_get (G_VARIANT_TYPE (tmp));
1409     g_free (tmp);
1410   }
1411 
1412   needed_size = g_variant_serialiser_needed_size (type_info,
1413                                                   random_instance_filler,
1414                                                   NULL, 0);
1415   g_assert_cmpint (needed_size, ==, 0);
1416 
1417   needed_size = g_variant_serialiser_needed_size (type_info,
1418                                                   random_instance_filler,
1419                                                   (gpointer *) &instance, 1);
1420 
1421   if (instance->is_fixed_sized)
1422     g_assert_cmpint (needed_size, ==, instance->size);
1423   else
1424     g_assert_cmpint (needed_size, ==, instance->size + 1);
1425 
1426   {
1427     guchar *ptr;
1428 
1429     ptr = data = align_malloc (needed_size);
1430     append_instance_data (instance, &ptr);
1431 
1432     if (!instance->is_fixed_sized)
1433       *ptr++ = '\0';
1434 
1435     g_assert_cmpint (ptr - data, ==, needed_size);
1436   }
1437 
1438   {
1439     guint alignment;
1440     gsize flavour;
1441 
1442     alignment = (instance->alignment & ALIGN_BITS) + 1;
1443 
1444     for (flavour = 0; flavour < 8; flavour += alignment)
1445       {
1446         GVariantSerialised serialised = { 0, };
1447         GVariantSerialised child;
1448 
1449         serialised.type_info = type_info;
1450         serialised.data = flavoured_malloc (needed_size, flavour);
1451         serialised.size = needed_size;
1452         serialised.depth = 0;
1453         serialised.ordered_offsets_up_to = 0;
1454         serialised.checked_offsets_up_to = 0;
1455 
1456         g_variant_serialiser_serialise (serialised,
1457                                         random_instance_filler,
1458                                         (gpointer *) &instance, 1);
1459 
1460         child = g_variant_serialised_get_child (serialised, 0);
1461         g_assert_true (child.type_info == instance->type_info);
1462         if (child.data != NULL)  /* could be NULL if element is non-normal */
1463           random_instance_assert (instance, child.data, child.size);
1464         g_variant_type_info_unref (child.type_info);
1465 
1466         flavoured_free (serialised.data, flavour);
1467       }
1468   }
1469 
1470   g_variant_type_info_unref (type_info);
1471   random_instance_free (instance);
1472   align_free (data);
1473 }
1474 
1475 static void
test_maybes(void)1476 test_maybes (void)
1477 {
1478   gsize i;
1479 
1480   for (i = 0; i < 1000; i++)
1481     test_maybe ();
1482 
1483   g_variant_type_info_assert_no_infos ();
1484 }
1485 
1486 static void
test_array(void)1487 test_array (void)
1488 {
1489   GVariantTypeInfo *element_info;
1490   GVariantTypeInfo *array_info;
1491   RandomInstance **instances;
1492   gsize needed_size;
1493   gsize offset_size;
1494   guint n_children;
1495   guchar *data;
1496 
1497   {
1498     gchar *element_type, *array_type;
1499 
1500     element_type = random_type_string ();
1501     array_type = g_strdup_printf ("a%s", element_type);
1502 
1503     element_info = g_variant_type_info_get (G_VARIANT_TYPE (element_type));
1504     array_info = g_variant_type_info_get (G_VARIANT_TYPE (array_type));
1505     g_assert_true (g_variant_type_info_element (array_info) == element_info);
1506 
1507     g_free (element_type);
1508     g_free (array_type);
1509   }
1510 
1511   {
1512     gsize i;
1513 
1514     n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN);
1515     instances = g_new (RandomInstance *, n_children);
1516     for (i = 0; i < n_children; i++)
1517       instances[i] = random_instance (element_info);
1518   }
1519 
1520   needed_size = g_variant_serialiser_needed_size (array_info,
1521                                                   random_instance_filler,
1522                                                   (gpointer *) instances,
1523                                                   n_children);
1524 
1525   {
1526     gsize element_fixed_size;
1527     gsize body_size = 0;
1528     gsize i;
1529 
1530     for (i = 0; i < n_children; i++)
1531       append_instance_size (instances[i], &body_size);
1532 
1533     g_variant_type_info_query (element_info, NULL, &element_fixed_size);
1534 
1535     if (!element_fixed_size)
1536       {
1537         offset_size = calculate_offset_size (body_size, n_children);
1538 
1539         if (offset_size == 0)
1540           offset_size = 1;
1541       }
1542     else
1543       offset_size = 0;
1544 
1545     g_assert_cmpint (needed_size, ==, body_size + n_children * offset_size);
1546   }
1547 
1548   {
1549     guchar *offset_ptr, *body_ptr;
1550     gsize i;
1551 
1552     body_ptr = data = align_malloc (needed_size);
1553     offset_ptr = body_ptr + needed_size - offset_size * n_children;
1554 
1555     for (i = 0; i < n_children; i++)
1556       {
1557         append_instance_data (instances[i], &body_ptr);
1558         append_offset (&offset_ptr, body_ptr - data, offset_size);
1559       }
1560 
1561     g_assert_true (body_ptr == data + needed_size - offset_size * n_children);
1562     g_assert_true (offset_ptr == data + needed_size);
1563   }
1564 
1565   {
1566     guint alignment;
1567     gsize flavour;
1568     gsize i;
1569 
1570     g_variant_type_info_query (array_info, &alignment, NULL);
1571     alignment = (alignment & ALIGN_BITS) + 1;
1572 
1573     for (flavour = 0; flavour < 8; flavour += alignment)
1574       {
1575         GVariantSerialised serialised = { 0, };
1576 
1577         serialised.type_info = array_info;
1578         serialised.data = flavoured_malloc (needed_size, flavour);
1579         serialised.size = needed_size;
1580         serialised.depth = 0;
1581         serialised.ordered_offsets_up_to = 0;
1582         serialised.checked_offsets_up_to = 0;
1583 
1584         g_variant_serialiser_serialise (serialised, random_instance_filler,
1585                                         (gpointer *) instances, n_children);
1586 
1587         if (serialised.size)
1588           g_assert_cmpint (memcmp (serialised.data, data, serialised.size), ==, 0);
1589 
1590         g_assert_cmpuint (g_variant_serialised_n_children (serialised), ==, n_children);
1591 
1592         for (i = 0; i < n_children; i++)
1593           {
1594             GVariantSerialised child;
1595 
1596             child = g_variant_serialised_get_child (serialised, i);
1597             g_assert_true (child.type_info == instances[i]->type_info);
1598             if (child.data != NULL)  /* could be NULL if element is non-normal */
1599               random_instance_assert (instances[i], child.data, child.size);
1600             g_variant_type_info_unref (child.type_info);
1601           }
1602 
1603         flavoured_free (serialised.data, flavour);
1604       }
1605   }
1606 
1607   {
1608     gsize i;
1609 
1610     for (i = 0; i < n_children; i++)
1611       random_instance_free (instances[i]);
1612     g_free (instances);
1613   }
1614 
1615   g_variant_type_info_unref (element_info);
1616   g_variant_type_info_unref (array_info);
1617   align_free (data);
1618 }
1619 
1620 static void
test_arrays(void)1621 test_arrays (void)
1622 {
1623   gsize i;
1624 
1625   for (i = 0; i < 100; i++)
1626     test_array ();
1627 
1628   g_variant_type_info_assert_no_infos ();
1629 }
1630 
1631 static void
test_tuple(void)1632 test_tuple (void)
1633 {
1634   GVariantTypeInfo *type_info;
1635   RandomInstance **instances;
1636   gboolean fixed_size;
1637   gsize needed_size;
1638   gsize offset_size;
1639   guint n_children;
1640   guint alignment;
1641   guchar *data;
1642 
1643   n_children = g_test_rand_int_range (0, MAX_TUPLE_CHILDREN);
1644   instances = g_new (RandomInstance *, n_children);
1645 
1646   {
1647     GString *type_string;
1648     gsize i;
1649 
1650     fixed_size = TRUE;
1651     alignment = 0;
1652 
1653     type_string = g_string_new ("(");
1654     for (i = 0; i < n_children; i++)
1655       {
1656         const gchar *str;
1657 
1658         instances[i] = random_instance (NULL);
1659 
1660         alignment |= instances[i]->alignment;
1661         if (!instances[i]->is_fixed_sized)
1662           fixed_size = FALSE;
1663 
1664         str = g_variant_type_info_get_type_string (instances[i]->type_info);
1665         g_string_append (type_string, str);
1666       }
1667     g_string_append_c (type_string, ')');
1668 
1669     type_info = g_variant_type_info_get (G_VARIANT_TYPE (type_string->str));
1670     g_string_free (type_string, TRUE);
1671   }
1672 
1673   needed_size = g_variant_serialiser_needed_size (type_info,
1674                                                   random_instance_filler,
1675                                                   (gpointer *) instances,
1676                                                   n_children);
1677   {
1678     gsize body_size = 0;
1679     gsize offsets = 0;
1680     gsize i;
1681 
1682     for (i = 0; i < n_children; i++)
1683       {
1684         append_instance_size (instances[i], &body_size);
1685 
1686         if (i != n_children - 1 && !instances[i]->is_fixed_sized)
1687           offsets++;
1688       }
1689 
1690     if (fixed_size)
1691       {
1692         body_size += (-body_size) & alignment;
1693 
1694         g_assert_true ((body_size == 0) == (n_children == 0));
1695         if (n_children == 0)
1696           body_size = 1;
1697       }
1698 
1699     offset_size = calculate_offset_size (body_size, offsets);
1700     g_assert_cmpint (needed_size, ==, body_size + offsets * offset_size);
1701   }
1702 
1703   {
1704     guchar *body_ptr;
1705     guchar *ofs_ptr;
1706     gsize i;
1707 
1708     body_ptr = data = align_malloc (needed_size);
1709     ofs_ptr = body_ptr + needed_size;
1710 
1711     for (i = 0; i < n_children; i++)
1712       {
1713         append_instance_data (instances[i], &body_ptr);
1714 
1715         if (i != n_children - 1 && !instances[i]->is_fixed_sized)
1716           prepend_offset (&ofs_ptr, body_ptr - data, offset_size);
1717       }
1718 
1719     if (fixed_size)
1720       {
1721         while (((gsize) body_ptr) & alignment)
1722           *body_ptr++ = '\0';
1723 
1724         g_assert_true ((body_ptr == data) == (n_children == 0));
1725         if (n_children == 0)
1726           *body_ptr++ = '\0';
1727 
1728       }
1729 
1730 
1731     g_assert_true (body_ptr == ofs_ptr);
1732   }
1733 
1734   {
1735     gsize flavour;
1736     gsize i;
1737 
1738     alignment = (alignment & ALIGN_BITS) + 1;
1739 
1740     for (flavour = 0; flavour < 8; flavour += alignment)
1741       {
1742         GVariantSerialised serialised = { 0, };
1743 
1744         serialised.type_info = type_info;
1745         serialised.data = flavoured_malloc (needed_size, flavour);
1746         serialised.size = needed_size;
1747         serialised.depth = 0;
1748         serialised.ordered_offsets_up_to = 0;
1749         serialised.checked_offsets_up_to = 0;
1750 
1751         g_variant_serialiser_serialise (serialised, random_instance_filler,
1752                                         (gpointer *) instances, n_children);
1753 
1754         if (serialised.size)
1755           g_assert_cmpint (memcmp (serialised.data, data, serialised.size), ==, 0);
1756 
1757         g_assert_cmpuint (g_variant_serialised_n_children (serialised), ==, n_children);
1758 
1759         for (i = 0; i < n_children; i++)
1760           {
1761             GVariantSerialised child;
1762 
1763             child = g_variant_serialised_get_child (serialised, i);
1764             g_assert_true (child.type_info == instances[i]->type_info);
1765             if (child.data != NULL)  /* could be NULL if element is non-normal */
1766               random_instance_assert (instances[i], child.data, child.size);
1767             g_variant_type_info_unref (child.type_info);
1768           }
1769 
1770         flavoured_free (serialised.data, flavour);
1771       }
1772   }
1773 
1774   {
1775     gsize i;
1776 
1777     for (i = 0; i < n_children; i++)
1778       random_instance_free (instances[i]);
1779     g_free (instances);
1780   }
1781 
1782   g_variant_type_info_unref (type_info);
1783   align_free (data);
1784 }
1785 
1786 static void
test_tuples(void)1787 test_tuples (void)
1788 {
1789   gsize i;
1790 
1791   for (i = 0; i < 100; i++)
1792     test_tuple ();
1793 
1794   g_variant_type_info_assert_no_infos ();
1795 }
1796 
1797 static void
test_variant(void)1798 test_variant (void)
1799 {
1800   GVariantTypeInfo *type_info;
1801   RandomInstance *instance;
1802   const gchar *type_string;
1803   gsize needed_size;
1804   guchar *data;
1805   gsize len;
1806 
1807   type_info = g_variant_type_info_get (G_VARIANT_TYPE_VARIANT);
1808   instance = random_instance (NULL);
1809 
1810   type_string = g_variant_type_info_get_type_string (instance->type_info);
1811   len = strlen (type_string);
1812 
1813   needed_size = g_variant_serialiser_needed_size (type_info,
1814                                                   random_instance_filler,
1815                                                   (gpointer *) &instance, 1);
1816 
1817   g_assert_cmpint (needed_size, ==, instance->size + 1 + len);
1818 
1819   {
1820     guchar *ptr;
1821 
1822     ptr = data = align_malloc (needed_size);
1823     append_instance_data (instance, &ptr);
1824     *ptr++ = '\0';
1825     memcpy (ptr, type_string, len);
1826     ptr += len;
1827 
1828     g_assert_true (data + needed_size == ptr);
1829   }
1830 
1831   {
1832     gsize alignment;
1833     gsize flavour;
1834 
1835     /* variants are always 8-aligned */
1836     alignment = ALIGN_BITS + 1;
1837 
1838     for (flavour = 0; flavour < 8; flavour += alignment)
1839       {
1840         GVariantSerialised serialised = { 0, };
1841         GVariantSerialised child;
1842 
1843         serialised.type_info = type_info;
1844         serialised.data = flavoured_malloc (needed_size, flavour);
1845         serialised.size = needed_size;
1846         serialised.depth = 0;
1847         serialised.ordered_offsets_up_to = 0;
1848         serialised.checked_offsets_up_to = 0;
1849 
1850         g_variant_serialiser_serialise (serialised, random_instance_filler,
1851                                         (gpointer *) &instance, 1);
1852 
1853         if (serialised.size)
1854           g_assert_cmpint (memcmp (serialised.data, data, serialised.size), ==, 0);
1855 
1856         g_assert_cmpuint (g_variant_serialised_n_children (serialised), ==, 1);
1857 
1858         child = g_variant_serialised_get_child (serialised, 0);
1859         g_assert_true (child.type_info == instance->type_info);
1860         random_instance_check (instance, child.data, child.size);
1861 
1862         g_variant_type_info_unref (child.type_info);
1863         flavoured_free (serialised.data, flavour);
1864       }
1865   }
1866 
1867   g_variant_type_info_unref (type_info);
1868   random_instance_free (instance);
1869   align_free (data);
1870 }
1871 
1872 static void
test_variants(void)1873 test_variants (void)
1874 {
1875   gsize i;
1876 
1877   for (i = 0; i < 100; i++)
1878     test_variant ();
1879 
1880   g_variant_type_info_assert_no_infos ();
1881 }
1882 
1883 static void
test_strings(void)1884 test_strings (void)
1885 {
1886   struct {
1887     guint flags;
1888     guint size;
1889     gconstpointer data;
1890   } test_cases[] = {
1891 #define is_nval           0
1892 #define is_string         1
1893 #define is_objpath        is_string | 2
1894 #define is_sig            is_string | 4
1895     { is_sig,       1, "" },
1896     { is_nval,      0, NULL },
1897     { is_nval,     13, "hello\xffworld!" },
1898     { is_string,   13, "hello world!" },
1899     { is_nval,     13, "hello world\0" },
1900     { is_nval,     13, "hello\0world!" },
1901     { is_nval,     12, "hello world!" },
1902     { is_nval,     13, "hello world!\xff" },
1903 
1904     { is_objpath,   2, "/" },
1905     { is_objpath,   3, "/a" },
1906     { is_string,    3, "//" },
1907     { is_objpath,  11, "/some/path" },
1908     { is_string,   12, "/some/path/" },
1909     { is_nval,     11, "/some\0path" },
1910     { is_string,   11, "/some\\path" },
1911     { is_string,   12, "/some//path" },
1912     { is_string,   12, "/some-/path" },
1913 
1914     { is_sig,       2, "i" },
1915     { is_sig,       2, "s" },
1916     { is_sig,       5, "(si)" },
1917     { is_string,    4, "(si" },
1918     { is_string,    2, "*" },
1919     { is_sig,       3, "ai" },
1920     { is_string,    3, "mi" },
1921     { is_string,    2, "r" },
1922     { is_sig,      15, "(yyy{sv}ssiai)" },
1923     { is_string,   16, "(yyy{yv}ssiai))" },
1924     { is_string,   15, "(yyy{vv}ssiai)" },
1925     { is_string,   15, "(yyy{sv)ssiai}" }
1926   };
1927   gsize i;
1928 
1929   for (i = 0; i < G_N_ELEMENTS (test_cases); i++)
1930     {
1931       guint flags;
1932 
1933       flags = g_variant_serialiser_is_string (test_cases[i].data,
1934                                               test_cases[i].size)
1935         ? 1 : 0;
1936 
1937       flags |= g_variant_serialiser_is_object_path (test_cases[i].data,
1938                                                     test_cases[i].size)
1939         ? 2 : 0;
1940 
1941       flags |= g_variant_serialiser_is_signature (test_cases[i].data,
1942                                                   test_cases[i].size)
1943         ? 4 : 0;
1944 
1945       g_assert_cmpuint (flags, ==, test_cases[i].flags);
1946     }
1947 }
1948 
1949 typedef struct _TreeInstance TreeInstance;
1950 struct _TreeInstance
1951 {
1952   GVariantTypeInfo *info;
1953 
1954   TreeInstance **children;
1955   gsize n_children;
1956 
1957   union {
1958     guint64 integer;
1959     gdouble floating;
1960     gchar string[200];
1961   } data;
1962   gsize data_size;
1963 };
1964 
1965 static GVariantType *
make_random_definite_type(int depth)1966 make_random_definite_type (int depth)
1967 {
1968   GString *description;
1969   GString *type_string;
1970   GVariantType *type;
1971 
1972   description = g_string_new (NULL);
1973   type_string = g_string_new (NULL);
1974   type = append_type_string (type_string, description, TRUE, depth);
1975   g_string_free (description, TRUE);
1976   g_string_free (type_string, TRUE);
1977 
1978   return type;
1979 }
1980 
1981 static void
make_random_string(gchar * string,gsize size,const GVariantType * type)1982 make_random_string (gchar              *string,
1983                     gsize               size,
1984                     const GVariantType *type)
1985 {
1986   gsize i;
1987 
1988   /* create strings that are valid signature strings */
1989 #define good_chars "bynqiuxthdsog"
1990 
1991   for (i = 0; i < size - 1; i++)
1992     string[i] = good_chars[g_test_rand_int_range (0, strlen (good_chars))];
1993   string[i] = '\0';
1994 
1995   /* in case we need an object path, prefix a '/' */
1996   if (*g_variant_type_peek_string (type) == 'o')
1997     string[0] = '/';
1998 
1999 #undef good_chars
2000 }
2001 
2002 static TreeInstance *
tree_instance_new(const GVariantType * type,int depth)2003 tree_instance_new (const GVariantType *type,
2004                    int                 depth)
2005 {
2006   const GVariantType *child_type = NULL;
2007   GVariantType *mytype = NULL;
2008   TreeInstance *instance;
2009   gboolean is_tuple_type;
2010 
2011   if (type == NULL)
2012     type = mytype = make_random_definite_type (depth);
2013 
2014   instance = g_slice_new (TreeInstance);
2015   instance->info = g_variant_type_info_get (type);
2016   instance->children = NULL;
2017   instance->n_children = 0;
2018   instance->data_size = 0;
2019 
2020   is_tuple_type = FALSE;
2021 
2022   switch (*g_variant_type_peek_string (type))
2023     {
2024     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2025       instance->n_children = g_test_rand_int_range (0, 2);
2026       child_type = g_variant_type_element (type);
2027       break;
2028 
2029     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2030       instance->n_children = g_test_rand_int_range (0, MAX_ARRAY_CHILDREN);
2031       child_type = g_variant_type_element (type);
2032       break;
2033 
2034     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2035     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2036       instance->n_children = g_variant_type_n_items (type);
2037       child_type = g_variant_type_first (type);
2038       is_tuple_type = TRUE;
2039       break;
2040 
2041     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2042       instance->n_children = 1;
2043       child_type = NULL;
2044       break;
2045 
2046     case 'b':
2047       instance->data.integer = g_test_rand_int_range (0, 2);
2048       instance->data_size = 1;
2049       break;
2050 
2051     case 'y':
2052       instance->data.integer = g_test_rand_int ();
2053       instance->data_size = 1;
2054       break;
2055 
2056     case 'n': case 'q':
2057       instance->data.integer = g_test_rand_int ();
2058       instance->data_size = 2;
2059       break;
2060 
2061     case 'i': case 'u': case 'h':
2062       instance->data.integer = g_test_rand_int ();
2063       instance->data_size = 4;
2064       break;
2065 
2066     case 'x': case 't':
2067       instance->data.integer = g_test_rand_int ();
2068       instance->data.integer <<= 32;
2069       instance->data.integer |= (guint32) g_test_rand_int ();
2070       instance->data_size = 8;
2071       break;
2072 
2073     case 'd':
2074       instance->data.floating = g_test_rand_double ();
2075       instance->data_size = 8;
2076       break;
2077 
2078     case 's': case 'o': case 'g':
2079       instance->data_size = g_test_rand_int_range (10, 200);
2080       make_random_string (instance->data.string, instance->data_size, type);
2081       break;
2082     }
2083 
2084   if (instance->data_size == 0)
2085     /* no data -> it is a container */
2086     {
2087       gsize i;
2088 
2089       instance->children = g_new (TreeInstance *, instance->n_children);
2090 
2091       for (i = 0; i < instance->n_children; i++)
2092         {
2093           instance->children[i] = tree_instance_new (child_type, depth - 1);
2094 
2095           if (is_tuple_type)
2096             child_type = g_variant_type_next (child_type);
2097         }
2098 
2099       g_assert_true (!is_tuple_type || child_type == NULL);
2100     }
2101 
2102   g_variant_type_free (mytype);
2103 
2104   return instance;
2105 }
2106 
2107 static void
tree_instance_free(TreeInstance * instance)2108 tree_instance_free (TreeInstance *instance)
2109 {
2110   gsize i;
2111 
2112   g_variant_type_info_unref (instance->info);
2113   for (i = 0; i < instance->n_children; i++)
2114     tree_instance_free (instance->children[i]);
2115   g_free (instance->children);
2116   g_slice_free (TreeInstance, instance);
2117 }
2118 
2119 static gboolean i_am_writing_byteswapped;
2120 
2121 static void
tree_filler(GVariantSerialised * serialised,gpointer data)2122 tree_filler (GVariantSerialised *serialised,
2123              gpointer            data)
2124 {
2125   TreeInstance *instance = data;
2126 
2127   if (serialised->type_info == NULL)
2128     serialised->type_info = instance->info;
2129 
2130   serialised->depth = 0;
2131 
2132   if (instance->data_size == 0)
2133     /* is a container */
2134     {
2135       if (serialised->size == 0)
2136         serialised->size =
2137           g_variant_serialiser_needed_size (instance->info, tree_filler,
2138                                             (gpointer *) instance->children,
2139                                             instance->n_children);
2140 
2141       if (serialised->data)
2142         g_variant_serialiser_serialise (*serialised, tree_filler,
2143                                         (gpointer *) instance->children,
2144                                         instance->n_children);
2145     }
2146   else
2147     /* it is a leaf */
2148     {
2149       if (serialised->size == 0)
2150         serialised->size = instance->data_size;
2151 
2152       if (serialised->data)
2153         {
2154           switch (instance->data_size)
2155             {
2156             case 1:
2157               *serialised->data = instance->data.integer;
2158               break;
2159 
2160             case 2:
2161               {
2162                 guint16 value = instance->data.integer;
2163 
2164                 if (i_am_writing_byteswapped)
2165                   value = GUINT16_SWAP_LE_BE (value);
2166 
2167                 *(guint16 *) serialised->data = value;
2168               }
2169               break;
2170 
2171             case 4:
2172               {
2173                 guint32 value = instance->data.integer;
2174 
2175                 if (i_am_writing_byteswapped)
2176                   value = GUINT32_SWAP_LE_BE (value);
2177 
2178                 *(guint32 *) serialised->data = value;
2179               }
2180               break;
2181 
2182             case 8:
2183               {
2184                 guint64 value = instance->data.integer;
2185 
2186                 if (i_am_writing_byteswapped)
2187                   value = GUINT64_SWAP_LE_BE (value);
2188 
2189                 *(guint64 *) serialised->data = value;
2190               }
2191               break;
2192 
2193             default:
2194               memcpy (serialised->data,
2195                       instance->data.string,
2196                       instance->data_size);
2197               break;
2198             }
2199         }
2200     }
2201 }
2202 
2203 static gboolean
check_tree(TreeInstance * instance,GVariantSerialised serialised)2204 check_tree (TreeInstance       *instance,
2205             GVariantSerialised  serialised)
2206 {
2207   if (instance->info != serialised.type_info)
2208     return FALSE;
2209 
2210   if (instance->data_size == 0)
2211     /* is a container */
2212     {
2213       gsize i;
2214 
2215       if (g_variant_serialised_n_children (serialised) !=
2216           instance->n_children)
2217         return FALSE;
2218 
2219       for (i = 0; i < instance->n_children; i++)
2220         {
2221           GVariantSerialised child;
2222           gpointer data = NULL;
2223           gboolean ok;
2224 
2225           child = g_variant_serialised_get_child (serialised, i);
2226           if (child.size && child.data == NULL)
2227             child.data = data = g_malloc0 (child.size);
2228           ok = check_tree (instance->children[i], child);
2229           g_variant_type_info_unref (child.type_info);
2230           g_free (data);
2231 
2232           if (!ok)
2233             return FALSE;
2234         }
2235 
2236       return TRUE;
2237     }
2238   else
2239     /* it is a leaf */
2240     {
2241       switch (instance->data_size)
2242         {
2243         case 1:
2244           g_assert_cmpuint (serialised.size, ==, 1);
2245           return *(guint8 *) serialised.data ==
2246                   (guint8) instance->data.integer;
2247 
2248         case 2:
2249           g_assert_cmpuint (serialised.size, ==, 2);
2250           return *(guint16 *) serialised.data ==
2251                   (guint16) instance->data.integer;
2252 
2253         case 4:
2254           g_assert_cmpuint (serialised.size, ==, 4);
2255           return *(guint32 *) serialised.data ==
2256                   (guint32) instance->data.integer;
2257 
2258         case 8:
2259           g_assert_cmpuint (serialised.size, ==, 8);
2260           return *(guint64 *) serialised.data ==
2261                   (guint64) instance->data.integer;
2262 
2263         default:
2264           if (serialised.size != instance->data_size)
2265             return FALSE;
2266 
2267           return memcmp (serialised.data,
2268                          instance->data.string,
2269                          instance->data_size) == 0;
2270         }
2271     }
2272 }
2273 
2274 static void
serialise_tree(TreeInstance * tree,GVariantSerialised * serialised)2275 serialise_tree (TreeInstance       *tree,
2276                 GVariantSerialised *serialised)
2277 {
2278   GVariantSerialised empty = {0, };
2279 
2280   *serialised = empty;
2281   tree_filler (serialised, tree);
2282   serialised->data = g_malloc (serialised->size);
2283   tree_filler (serialised, tree);
2284 }
2285 
2286 static void
test_byteswap(void)2287 test_byteswap (void)
2288 {
2289   GVariantSerialised one = { 0, }, two = { 0, }, three = { 0, };
2290   TreeInstance *tree;
2291   GVariant *one_variant = NULL;
2292   GVariant *two_variant = NULL;
2293   GVariant *two_byteswapped = NULL;
2294   GVariant *three_variant = NULL;
2295   GVariant *three_byteswapped = NULL;
2296   guint8 *three_data_copy = NULL;
2297   gsize three_size_copy = 0;
2298 
2299   /* Write a tree out twice, once normally and once byteswapped. */
2300   tree = tree_instance_new (NULL, 3);
2301   serialise_tree (tree, &one);
2302 
2303   one_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (one.type_info)),
2304                                          one.data, one.size, FALSE, NULL, NULL);
2305 
2306   i_am_writing_byteswapped = TRUE;
2307   serialise_tree (tree, &two);
2308   serialise_tree (tree, &three);
2309   i_am_writing_byteswapped = FALSE;
2310 
2311   /* Swap the first byteswapped one back using the function we want to test. */
2312   two_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (two.type_info)),
2313                                          two.data, two.size, FALSE, NULL, NULL);
2314   two_byteswapped = g_variant_byteswap (two_variant);
2315 
2316   /* Make the second byteswapped one non-normal (hopefully), and then byteswap
2317    * it back using the function we want to test in its non-normal mode.
2318    * This might not work because it’s not necessarily possible to make an
2319    * arbitrary random variant non-normal. Adding a single zero byte to the end
2320    * often makes something non-normal but still readable. */
2321   three_size_copy = three.size + 1;
2322   three_data_copy = g_malloc (three_size_copy);
2323   memcpy (three_data_copy, three.data, three.size);
2324   three_data_copy[three.size] = '\0';
2325 
2326   three_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (three.type_info)),
2327                                            three_data_copy, three_size_copy, FALSE, NULL, NULL);
2328   three_byteswapped = g_variant_byteswap (three_variant);
2329 
2330   /* Check they’re the same. We can always compare @one_variant and
2331    * @two_byteswapped. We can only compare @two_byteswapped and
2332    * @three_byteswapped if @two_variant and @three_variant are equal: in that
2333    * case, the corruption to @three_variant was enough to make it non-normal but
2334    * not enough to change its value. */
2335   g_assert_cmpvariant (one_variant, two_byteswapped);
2336 
2337   if (g_variant_equal (two_variant, three_variant))
2338     g_assert_cmpvariant (two_byteswapped, three_byteswapped);
2339 
2340   g_variant_unref (three_byteswapped);
2341   g_variant_unref (three_variant);
2342   g_variant_unref (two_byteswapped);
2343   g_variant_unref (two_variant);
2344   g_variant_unref (one_variant);
2345   tree_instance_free (tree);
2346   g_free (one.data);
2347   g_free (two.data);
2348   g_free (three.data);
2349   g_free (three_data_copy);
2350 }
2351 
2352 static void
test_byteswaps(void)2353 test_byteswaps (void)
2354 {
2355   int i;
2356 
2357   for (i = 0; i < 200; i++)
2358     test_byteswap ();
2359 
2360   g_variant_type_info_assert_no_infos ();
2361 }
2362 
2363 static void
test_serialiser_children(void)2364 test_serialiser_children (void)
2365 {
2366   GBytes *data1, *data2;
2367   GVariant *child1, *child2;
2368   GVariantType *mv_type = g_variant_type_new_maybe (G_VARIANT_TYPE_VARIANT);
2369   GVariant *variant, *child;
2370 
2371   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1865");
2372   g_test_summary ("Test that getting a child variant before and after "
2373                   "serialisation of the parent works");
2374 
2375   /* Construct a variable sized array containing a child which serialises to a
2376    * zero-length bytestring. */
2377   child = g_variant_new_maybe (G_VARIANT_TYPE_VARIANT, NULL);
2378   variant = g_variant_new_array (mv_type, &child, 1);
2379 
2380   /* Get the child before serialising. */
2381   child1 = g_variant_get_child_value (variant, 0);
2382   data1 = g_variant_get_data_as_bytes (child1);
2383 
2384   /* Serialise the parent variant. */
2385   g_variant_get_data (variant);
2386 
2387   /* Get the child again after serialising — this uses a different code path. */
2388   child2 = g_variant_get_child_value (variant, 0);
2389   data2 = g_variant_get_data_as_bytes (child2);
2390 
2391   /* Check things are equal. */
2392   g_assert_cmpvariant (child1, child2);
2393   g_assert_true (g_bytes_equal (data1, data2));
2394 
2395   g_variant_unref (child2);
2396   g_variant_unref (child1);
2397   g_variant_unref (variant);
2398   g_bytes_unref (data2);
2399   g_bytes_unref (data1);
2400   g_variant_type_free (mv_type);
2401 }
2402 
2403 static void
test_fuzz(gdouble * fuzziness)2404 test_fuzz (gdouble *fuzziness)
2405 {
2406   GVariantSerialised serialised = { 0, };
2407   TreeInstance *tree;
2408 
2409   /* make an instance */
2410   tree = tree_instance_new (NULL, 3);
2411 
2412   /* serialise it */
2413   serialise_tree (tree, &serialised);
2414 
2415   g_assert_true (g_variant_serialised_is_normal (serialised));
2416   g_assert_true (check_tree (tree, serialised));
2417 
2418   if (serialised.size)
2419     {
2420       gboolean fuzzed = FALSE;
2421       gboolean a, b;
2422 
2423       while (!fuzzed)
2424         {
2425           gsize i;
2426 
2427           for (i = 0; i < serialised.size; i++)
2428             if (randomly (*fuzziness))
2429               {
2430                 serialised.data[i] += g_test_rand_int_range (1, 256);
2431                 fuzzed = TRUE;
2432               }
2433         }
2434 
2435       /* at least one byte in the serialised data has changed.
2436        *
2437        * this means that at least one of the following is true:
2438        *
2439        *    - the serialised data now represents a different value:
2440        *        check_tree() will return FALSE
2441        *
2442        *    - the serialised data is in non-normal form:
2443        *        g_variant_serialiser_is_normal() will return FALSE
2444        *
2445        * we always do both checks to increase exposure of the serialiser
2446        * to corrupt data.
2447        */
2448       a = g_variant_serialised_is_normal (serialised);
2449       b = check_tree (tree, serialised);
2450 
2451       g_assert_true (!a || !b);
2452     }
2453 
2454   tree_instance_free (tree);
2455   g_free (serialised.data);
2456 }
2457 
2458 
2459 static void
test_fuzzes(gpointer data)2460 test_fuzzes (gpointer data)
2461 {
2462   gdouble fuzziness;
2463   int i;
2464 
2465   fuzziness = GPOINTER_TO_INT (data) / 100.;
2466 
2467   for (i = 0; i < 200; i++)
2468     test_fuzz (&fuzziness);
2469 
2470   g_variant_type_info_assert_no_infos ();
2471 }
2472 
2473 static GVariant *
tree_instance_get_gvariant(TreeInstance * tree)2474 tree_instance_get_gvariant (TreeInstance *tree)
2475 {
2476   const GVariantType *type;
2477   GVariant *result;
2478 
2479   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2480 
2481   switch (g_variant_type_info_get_type_char (tree->info))
2482     {
2483     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2484       {
2485         const GVariantType *child_type;
2486         GVariant *child;
2487 
2488         if (tree->n_children)
2489           child = tree_instance_get_gvariant (tree->children[0]);
2490         else
2491           child = NULL;
2492 
2493         child_type = g_variant_type_element (type);
2494 
2495         if (child != NULL && randomly (0.5))
2496           child_type = NULL;
2497 
2498         result = g_variant_new_maybe (child_type, child);
2499       }
2500       break;
2501 
2502     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2503       {
2504         const GVariantType *child_type;
2505         GVariant **children;
2506         gsize i;
2507 
2508         children = g_new (GVariant *, tree->n_children);
2509         for (i = 0; i < tree->n_children; i++)
2510           children[i] = tree_instance_get_gvariant (tree->children[i]);
2511 
2512         child_type = g_variant_type_element (type);
2513 
2514         if (i > 0 && randomly (0.5))
2515           child_type = NULL;
2516 
2517         result = g_variant_new_array (child_type, children, tree->n_children);
2518         g_free (children);
2519       }
2520       break;
2521 
2522     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2523       {
2524         GVariant **children;
2525         gsize i;
2526 
2527         children = g_new (GVariant *, tree->n_children);
2528         for (i = 0; i < tree->n_children; i++)
2529           children[i] = tree_instance_get_gvariant (tree->children[i]);
2530 
2531         result = g_variant_new_tuple (children, tree->n_children);
2532         g_free (children);
2533       }
2534       break;
2535 
2536     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2537       {
2538         GVariant *key, *val;
2539 
2540         g_assert_cmpuint (tree->n_children, ==, 2);
2541 
2542         key = tree_instance_get_gvariant (tree->children[0]);
2543         val = tree_instance_get_gvariant (tree->children[1]);
2544 
2545         result = g_variant_new_dict_entry (key, val);
2546       }
2547       break;
2548 
2549     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2550       {
2551         GVariant *value;
2552 
2553         g_assert_cmpuint (tree->n_children, ==, 1);
2554 
2555         value = tree_instance_get_gvariant (tree->children[0]);
2556         result = g_variant_new_variant (value);
2557       }
2558       break;
2559 
2560     case 'b':
2561       result = g_variant_new_boolean (tree->data.integer > 0);
2562       break;
2563 
2564     case 'y':
2565       result = g_variant_new_byte (tree->data.integer);
2566       break;
2567 
2568     case 'n':
2569       result = g_variant_new_int16 (tree->data.integer);
2570       break;
2571 
2572     case 'q':
2573       result = g_variant_new_uint16 (tree->data.integer);
2574       break;
2575 
2576     case 'i':
2577       result = g_variant_new_int32 (tree->data.integer);
2578       break;
2579 
2580     case 'u':
2581       result = g_variant_new_uint32 (tree->data.integer);
2582       break;
2583 
2584     case 'x':
2585       result = g_variant_new_int64 (tree->data.integer);
2586       break;
2587 
2588     case 't':
2589       result = g_variant_new_uint64 (tree->data.integer);
2590       break;
2591 
2592     case 'h':
2593       result = g_variant_new_handle (tree->data.integer);
2594       break;
2595 
2596     case 'd':
2597       result = g_variant_new_double (tree->data.floating);
2598       break;
2599 
2600     case 's':
2601       result = g_variant_new_string (tree->data.string);
2602       break;
2603 
2604     case 'o':
2605       result = g_variant_new_object_path (tree->data.string);
2606       break;
2607 
2608     case 'g':
2609       result = g_variant_new_signature (tree->data.string);
2610       break;
2611 
2612     default:
2613       g_assert_not_reached ();
2614     }
2615 
2616   return result;
2617 }
2618 
2619 static gboolean
tree_instance_check_gvariant(TreeInstance * tree,GVariant * value)2620 tree_instance_check_gvariant (TreeInstance *tree,
2621                               GVariant     *value)
2622 {
2623   const GVariantType *type;
2624 
2625   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2626   g_assert_true (g_variant_is_of_type (value, type));
2627 
2628   switch (g_variant_type_info_get_type_char (tree->info))
2629     {
2630     case G_VARIANT_TYPE_INFO_CHAR_MAYBE:
2631       {
2632         GVariant *child;
2633         gboolean equal;
2634 
2635         child = g_variant_get_maybe (value);
2636 
2637         if (child != NULL && tree->n_children == 1)
2638           equal = tree_instance_check_gvariant (tree->children[0], child);
2639         else if (child == NULL && tree->n_children == 0)
2640           equal = TRUE;
2641         else
2642           equal = FALSE;
2643 
2644         if (child != NULL)
2645           g_variant_unref (child);
2646 
2647         return equal;
2648       }
2649       break;
2650 
2651     case G_VARIANT_TYPE_INFO_CHAR_ARRAY:
2652     case G_VARIANT_TYPE_INFO_CHAR_TUPLE:
2653     case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:
2654       {
2655         gsize i;
2656 
2657         if (g_variant_n_children (value) != tree->n_children)
2658           return FALSE;
2659 
2660         for (i = 0; i < tree->n_children; i++)
2661           {
2662             GVariant *child;
2663             gboolean equal;
2664 
2665             child = g_variant_get_child_value (value, i);
2666             equal = tree_instance_check_gvariant (tree->children[i], child);
2667             g_variant_unref (child);
2668 
2669             if (!equal)
2670               return FALSE;
2671           }
2672 
2673         return TRUE;
2674       }
2675       break;
2676 
2677     case G_VARIANT_TYPE_INFO_CHAR_VARIANT:
2678       {
2679         const gchar *str1, *str2;
2680         GVariant *child;
2681         gboolean equal;
2682 
2683         child = g_variant_get_variant (value);
2684         str1 = g_variant_get_type_string (child);
2685         str2 = g_variant_type_info_get_type_string (tree->children[0]->info);
2686         /* GVariant only keeps one copy of type strings around */
2687         equal = str1 == str2 &&
2688                 tree_instance_check_gvariant (tree->children[0], child);
2689 
2690         g_variant_unref (child);
2691 
2692         return equal;
2693       }
2694       break;
2695 
2696     case 'b':
2697       return g_variant_get_boolean (value) == (gboolean) tree->data.integer;
2698 
2699     case 'y':
2700       return g_variant_get_byte (value) == (guchar) tree->data.integer;
2701 
2702     case 'n':
2703       return g_variant_get_int16 (value) == (gint16) tree->data.integer;
2704 
2705     case 'q':
2706       return g_variant_get_uint16 (value) == (guint16) tree->data.integer;
2707 
2708     case 'i':
2709       return g_variant_get_int32 (value) == (gint32) tree->data.integer;
2710 
2711     case 'u':
2712       return g_variant_get_uint32 (value) == (guint32) tree->data.integer;
2713 
2714     case 'x':
2715       return g_variant_get_int64 (value) == (gint64) tree->data.integer;
2716 
2717     case 't':
2718       return g_variant_get_uint64 (value) == (guint64) tree->data.integer;
2719 
2720     case 'h':
2721       return g_variant_get_handle (value) == (gint32) tree->data.integer;
2722 
2723     case 'd':
2724       {
2725         gdouble floating = g_variant_get_double (value);
2726 
2727         return memcmp (&floating, &tree->data.floating, sizeof floating) == 0;
2728       }
2729 
2730     case 's':
2731     case 'o':
2732     case 'g':
2733       return strcmp (g_variant_get_string (value, NULL),
2734                      tree->data.string) == 0;
2735 
2736     default:
2737       g_assert_not_reached ();
2738     }
2739 }
2740 
2741 static void
tree_instance_build_gvariant(TreeInstance * tree,GVariantBuilder * builder,gboolean guess_ok)2742 tree_instance_build_gvariant (TreeInstance    *tree,
2743                               GVariantBuilder *builder,
2744                               gboolean         guess_ok)
2745 {
2746   const GVariantType *type;
2747 
2748   type = (GVariantType *) g_variant_type_info_get_type_string (tree->info);
2749 
2750   if (g_variant_type_is_container (type))
2751     {
2752       gsize i;
2753 
2754       /* force GVariantBuilder to guess the type half the time */
2755       if (guess_ok && randomly (0.5))
2756         {
2757           if (g_variant_type_is_array (type) && tree->n_children)
2758             type = G_VARIANT_TYPE_ARRAY;
2759 
2760           if (g_variant_type_is_maybe (type) && tree->n_children)
2761             type = G_VARIANT_TYPE_MAYBE;
2762 
2763           if (g_variant_type_is_tuple (type))
2764             type = G_VARIANT_TYPE_TUPLE;
2765 
2766           if (g_variant_type_is_dict_entry (type))
2767             type = G_VARIANT_TYPE_DICT_ENTRY;
2768         }
2769       else
2770         guess_ok = FALSE;
2771 
2772       g_variant_builder_open (builder, type);
2773 
2774       for (i = 0; i < tree->n_children; i++)
2775         tree_instance_build_gvariant (tree->children[i], builder, guess_ok);
2776 
2777       g_variant_builder_close (builder);
2778     }
2779   else
2780     g_variant_builder_add_value (builder, tree_instance_get_gvariant (tree));
2781 }
2782 
2783 
2784 static gboolean
tree_instance_check_iter(TreeInstance * tree,GVariantIter * iter)2785 tree_instance_check_iter (TreeInstance *tree,
2786                           GVariantIter *iter)
2787 {
2788   GVariant *value;
2789 
2790   value = g_variant_iter_next_value (iter);
2791 
2792   if (g_variant_is_container (value))
2793     {
2794       gsize i;
2795 
2796       iter = g_variant_iter_new (value);
2797       g_variant_unref (value);
2798 
2799       if (g_variant_iter_n_children (iter) != tree->n_children)
2800         {
2801           g_variant_iter_free (iter);
2802           return FALSE;
2803         }
2804 
2805       for (i = 0; i < tree->n_children; i++)
2806         if (!tree_instance_check_iter (tree->children[i], iter))
2807           {
2808             g_variant_iter_free (iter);
2809             return FALSE;
2810           }
2811 
2812       g_assert_null (g_variant_iter_next_value (iter));
2813       g_variant_iter_free (iter);
2814 
2815       return TRUE;
2816     }
2817 
2818   else
2819     {
2820       gboolean equal;
2821 
2822       equal = tree_instance_check_gvariant (tree, value);
2823       g_variant_unref (value);
2824 
2825       return equal;
2826     }
2827 }
2828 
2829 static void
test_container(void)2830 test_container (void)
2831 {
2832   TreeInstance *tree;
2833   GVariant *value;
2834   gchar *s1, *s2;
2835 
2836   tree = tree_instance_new (NULL, 3);
2837   value = g_variant_ref_sink (tree_instance_get_gvariant (tree));
2838 
2839   s1 = g_variant_print (value, TRUE);
2840   g_assert_true (tree_instance_check_gvariant (tree, value));
2841 
2842   g_variant_get_data (value);
2843 
2844   s2 = g_variant_print (value, TRUE);
2845   g_assert_true (tree_instance_check_gvariant (tree, value));
2846 
2847   g_assert_cmpstr (s1, ==, s2);
2848 
2849   if (g_variant_is_container (value))
2850     {
2851       GVariantBuilder builder;
2852       GVariantIter iter;
2853       GVariant *built;
2854       GVariant *val;
2855       gchar *s3;
2856 
2857       g_variant_builder_init (&builder, G_VARIANT_TYPE_VARIANT);
2858       tree_instance_build_gvariant (tree, &builder, TRUE);
2859       built = g_variant_builder_end (&builder);
2860       g_variant_ref_sink (built);
2861       g_variant_get_data (built);
2862       val = g_variant_get_variant (built);
2863 
2864       s3 = g_variant_print (val, TRUE);
2865       g_assert_cmpstr (s1, ==, s3);
2866 
2867       g_variant_iter_init (&iter, built);
2868       g_assert_true (tree_instance_check_iter (tree, &iter));
2869       g_assert_null (g_variant_iter_next_value (&iter));
2870 
2871       g_variant_unref (built);
2872       g_variant_unref (val);
2873       g_free (s3);
2874     }
2875 
2876   tree_instance_free (tree);
2877   g_variant_unref (value);
2878   g_free (s2);
2879   g_free (s1);
2880 }
2881 
2882 static void
test_string(void)2883 test_string (void)
2884 {
2885   /* Test some different methods of creating strings */
2886   GVariant *v;
2887 
2888   v = g_variant_new_string ("foo");
2889   g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo");
2890   g_variant_unref (v);
2891 
2892 
2893   v = g_variant_new_take_string (g_strdup ("foo"));
2894   g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo");
2895   g_variant_unref (v);
2896 
2897   v = g_variant_new_printf ("%s %d", "foo", 123);
2898   g_assert_cmpstr (g_variant_get_string (v, NULL), ==, "foo 123");
2899   g_variant_unref (v);
2900 }
2901 
2902 static void
test_utf8(void)2903 test_utf8 (void)
2904 {
2905   const gchar invalid[] = "hello\xffworld";
2906   GVariant *value;
2907 
2908   /* ensure that the test data is not valid utf8... */
2909   g_assert_false (g_utf8_validate (invalid, -1, NULL));
2910 
2911   /* load the data untrusted */
2912   value = g_variant_new_from_data (G_VARIANT_TYPE_STRING,
2913                                    invalid, sizeof invalid,
2914                                    FALSE, NULL, NULL);
2915 
2916   /* ensure that the problem is caught and we get valid UTF-8 */
2917   g_assert_true (g_utf8_validate (g_variant_get_string (value, NULL), -1, NULL));
2918   g_variant_unref (value);
2919 
2920 
2921   /* now load it trusted */
2922   value = g_variant_new_from_data (G_VARIANT_TYPE_STRING,
2923                                    invalid, sizeof invalid,
2924                                    TRUE, NULL, NULL);
2925 
2926   /* ensure we get the invalid data (ie: make sure that time wasn't
2927    * wasted on validating data that was marked as trusted)
2928    */
2929   g_assert_true (g_variant_get_string (value, NULL) == invalid);
2930   g_variant_unref (value);
2931 }
2932 
2933 static void
test_containers(void)2934 test_containers (void)
2935 {
2936   gsize i;
2937 
2938   for (i = 0; i < 100; i++)
2939     {
2940       test_container ();
2941     }
2942 
2943   g_variant_type_info_assert_no_infos ();
2944 }
2945 
2946 static void
test_format_strings(void)2947 test_format_strings (void)
2948 {
2949   GVariantType *type;
2950   const gchar *end;
2951 
2952   g_assert_true (g_variant_format_string_scan ("i", NULL, &end) && *end == '\0');
2953   g_assert_true (g_variant_format_string_scan ("@i", NULL, &end) && *end == '\0');
2954   g_assert_true (g_variant_format_string_scan ("@ii", NULL, &end) && *end == 'i');
2955   g_assert_true (g_variant_format_string_scan ("^a&s", NULL, &end) && *end == '\0');
2956   g_assert_true (g_variant_format_string_scan ("(^as)", NULL, &end) &&
2957                  *end == '\0');
2958   g_assert_false (g_variant_format_string_scan ("(^s)", NULL, &end));
2959   g_assert_false (g_variant_format_string_scan ("(^a)", NULL, &end));
2960   g_assert_false (g_variant_format_string_scan ("(z)", NULL, &end));
2961   g_assert_false (g_variant_format_string_scan ("az", NULL, &end));
2962   g_assert_false (g_variant_format_string_scan ("{**}", NULL, &end));
2963   g_assert_false (g_variant_format_string_scan ("{@**}", NULL, &end));
2964   g_assert_true (g_variant_format_string_scan ("{@y*}", NULL, &end) &&
2965                  *end == '\0');
2966   g_assert_true (g_variant_format_string_scan ("{yv}", NULL, &end) &&
2967                  *end == '\0');
2968   g_assert_false (g_variant_format_string_scan ("{&?v}", NULL, &end));
2969   g_assert_true (g_variant_format_string_scan ("{@?v}", NULL, &end) &&
2970                  *end == '\0');
2971   g_assert_false (g_variant_format_string_scan ("{&@sv}", NULL, &end));
2972   g_assert_false (g_variant_format_string_scan ("{@&sv}", NULL, &end));
2973   g_assert_true (g_variant_format_string_scan ("{&sv}", NULL, &end) &&
2974                  *end == '\0');
2975   g_assert_false (g_variant_format_string_scan ("{vv}", NULL, &end));
2976   g_assert_false (g_variant_format_string_scan ("{y}", NULL, &end));
2977   g_assert_false (g_variant_format_string_scan ("{yyy}", NULL, &end));
2978   g_assert_false (g_variant_format_string_scan ("{ya}", NULL, &end));
2979   g_assert_true (g_variant_format_string_scan ("&s", NULL, &end) && *end == '\0');
2980   g_assert_false (g_variant_format_string_scan ("&as", NULL, &end));
2981   g_assert_false (g_variant_format_string_scan ("@z", NULL, &end));
2982   g_assert_false (g_variant_format_string_scan ("az", NULL, &end));
2983   g_assert_false (g_variant_format_string_scan ("a&s", NULL, &end));
2984 
2985   type = g_variant_format_string_scan_type ("mm(@xy^a&s*?@?)", NULL, &end);
2986   g_assert_true (type && *end == '\0');
2987   g_assert_true (g_variant_type_equal (type, G_VARIANT_TYPE ("mm(xyas*?\?)")));
2988   g_variant_type_free (type);
2989 
2990   type = g_variant_format_string_scan_type ("mm(@xy^a&*?@?)", NULL, NULL);
2991   g_assert_null (type);
2992 }
2993 
2994 static void
do_failed_test(const char * test,const gchar * pattern)2995 do_failed_test (const char *test,
2996                 const gchar *pattern)
2997 {
2998   g_test_trap_subprocess (test, 1000000, 0);
2999   g_test_trap_assert_failed ();
3000   g_test_trap_assert_stderr (pattern);
3001 }
3002 
3003 static void
test_invalid_varargs(void)3004 test_invalid_varargs (void)
3005 {
3006   GVariant *value;
3007   const gchar *end;
3008 
3009   if (!g_test_undefined ())
3010     return;
3011 
3012   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3013                          "*GVariant format string*");
3014   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3015                          "*valid_format_string*");
3016   value = g_variant_new ("z");
3017   g_test_assert_expected_messages ();
3018   g_assert_null (value);
3019 
3020   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3021                          "*valid GVariant format string as a prefix*");
3022   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3023                          "*valid_format_string*");
3024   value = g_variant_new_va ("z", &end, NULL);
3025   g_test_assert_expected_messages ();
3026   g_assert_null (value);
3027 
3028   value = g_variant_new ("y", 'a');
3029   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3030                          "*type of 'q' but * has a type of 'y'*");
3031   g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3032                          "*valid_format_string*");
3033   g_variant_get (value, "q");
3034   g_test_assert_expected_messages ();
3035   g_variant_unref (value);
3036 }
3037 
3038 static void
check_and_free(GVariant * value,const gchar * str)3039 check_and_free (GVariant    *value,
3040                 const gchar *str)
3041 {
3042   gchar *valstr = g_variant_print (value, FALSE);
3043   g_assert_cmpstr (str, ==, valstr);
3044   g_variant_unref (value);
3045   g_free (valstr);
3046 }
3047 
3048 static void
test_varargs_empty_array(void)3049 test_varargs_empty_array (void)
3050 {
3051   g_variant_new ("(a{s*})", NULL);
3052 
3053   g_assert_not_reached ();
3054 }
3055 
3056 static void
test_varargs(void)3057 test_varargs (void)
3058 {
3059   {
3060     GVariantBuilder array;
3061 
3062     g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
3063     g_variant_builder_add_parsed (&array, "{'size', <(%i, %i)> }", 800, 600);
3064     g_variant_builder_add (&array, "{sv}", "title",
3065                            g_variant_new_string ("Test case"));
3066     g_variant_builder_add_value (&array,
3067       g_variant_new_dict_entry (g_variant_new_string ("temperature"),
3068                                 g_variant_new_variant (
3069                                   g_variant_new_double (37.5))));
3070     check_and_free (g_variant_new ("(ma{sv}m(a{sv})ma{sv}ii)",
3071                                    NULL, FALSE, NULL, &array, 7777, 8888),
3072                     "(nothing, nothing, {'size': <(800, 600)>, "
3073                                         "'title': <'Test case'>, "
3074                                         "'temperature': <37.5>}, "
3075                      "7777, 8888)");
3076 
3077     check_and_free (g_variant_new ("(imimimmimmimmi)",
3078                                    123,
3079                                    FALSE, 321,
3080                                    TRUE, 123,
3081                                    FALSE, TRUE, 321,
3082                                    TRUE, FALSE, 321,
3083                                    TRUE, TRUE, 123),
3084                     "(123, nothing, 123, nothing, just nothing, 123)");
3085 
3086     check_and_free (g_variant_new ("(ybnixd)",
3087                                    'a', 1, 22, 33, (guint64) 44, 5.5),
3088                     "(0x61, true, 22, 33, 44, 5.5)");
3089 
3090     check_and_free (g_variant_new ("(@y?*rv)",
3091                                    g_variant_new ("y", 'a'),
3092                                    g_variant_new ("y", 'b'),
3093                                    g_variant_new ("y", 'c'),
3094                                    g_variant_new ("(y)", 'd'),
3095                                    g_variant_new ("y", 'e')),
3096                     "(0x61, 0x62, 0x63, (0x64,), <byte 0x65>)");
3097   }
3098 
3099   {
3100     GVariantBuilder array;
3101     GVariantIter iter;
3102     GVariant *value;
3103     gchar *number;
3104     gboolean just;
3105     guint i;
3106     gint val;
3107 
3108     g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
3109     for (i = 0; i < 100; i++)
3110       {
3111         number = g_strdup_printf ("%u", i);
3112         g_variant_builder_add (&array, "s", number);
3113         g_free (number);
3114       }
3115 
3116     value = g_variant_builder_end (&array);
3117     g_variant_iter_init (&iter, value);
3118 
3119     i = 0;
3120     while (g_variant_iter_loop (&iter, "s", &number))
3121       {
3122         gchar *check = g_strdup_printf ("%u", i++);
3123         g_assert_cmpstr (number, ==, check);
3124         g_free (check);
3125       }
3126     g_assert_null (number);
3127     g_assert_cmpuint (i, ==, 100);
3128 
3129     g_variant_unref (value);
3130 
3131     g_variant_builder_init (&array, G_VARIANT_TYPE_ARRAY);
3132     for (i = 0; i < 100; i++)
3133       g_variant_builder_add (&array, "mi", i % 2 == 0, i);
3134     value = g_variant_builder_end (&array);
3135 
3136     i = 0;
3137     g_variant_iter_init (&iter, value);
3138     while (g_variant_iter_loop (&iter, "mi", NULL, &val))
3139       g_assert_true (val == (gint) i++ || val == 0);
3140     g_assert_cmpuint (i, ==, 100);
3141 
3142     i = 0;
3143     g_variant_iter_init (&iter, value);
3144     while (g_variant_iter_loop (&iter, "mi", &just, &val))
3145       {
3146         gint this = i++;
3147 
3148         if (this % 2 == 0)
3149           {
3150             g_assert_true (just);
3151             g_assert_cmpint (val, ==, this);
3152           }
3153         else
3154           {
3155             g_assert_false (just);
3156             g_assert_cmpint (val, ==, 0);
3157           }
3158       }
3159     g_assert_cmpuint (i, ==, 100);
3160 
3161     g_variant_unref (value);
3162   }
3163 
3164   {
3165     const gchar *strvector[] = {"/hello", "/world", NULL};
3166     const gchar *test_strs[] = {"/foo", "/bar", "/baz" };
3167     GVariantBuilder builder;
3168     GVariantIter *array;
3169     GVariantIter tuple;
3170     const gchar **strv;
3171     gchar **my_strv;
3172     GVariant *value;
3173     gchar *str;
3174     gsize i;
3175 
3176     g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
3177     g_variant_builder_add (&builder, "s", test_strs[0]);
3178     g_variant_builder_add (&builder, "s", test_strs[1]);
3179     g_variant_builder_add (&builder, "s", test_strs[2]);
3180     value = g_variant_new ("(as^as^a&s)", &builder, strvector, strvector);
3181     g_variant_iter_init (&tuple, value);
3182     g_variant_iter_next (&tuple, "as", &array);
3183 
3184     i = 0;
3185     while (g_variant_iter_loop (array, "s", &str))
3186       g_assert_cmpstr (str, ==, test_strs[i++]);
3187     g_assert_cmpuint (i, ==, 3);
3188 
3189     g_variant_iter_free (array);
3190 
3191     /* start over */
3192     g_variant_iter_init (&tuple, value);
3193     g_variant_iter_next (&tuple, "as", &array);
3194 
3195     i = 0;
3196     while (g_variant_iter_loop (array, "&s", &str))
3197       g_assert_cmpstr (str, ==, test_strs[i++]);
3198     g_assert_cmpuint (i, ==, 3);
3199 
3200     g_variant_iter_free (array);
3201 
3202     g_variant_iter_next (&tuple, "^a&s", &strv);
3203     g_variant_iter_next (&tuple, "^as", &my_strv);
3204 
3205     g_assert_cmpstrv (strv, strvector);
3206     g_assert_cmpstrv (my_strv, strvector);
3207 
3208     g_variant_unref (value);
3209     g_strfreev (my_strv);
3210     g_free (strv);
3211   }
3212 
3213   {
3214     const gchar *strvector[] = {"/hello", "/world", NULL};
3215     const gchar *test_strs[] = {"/foo", "/bar", "/baz" };
3216     GVariantBuilder builder;
3217     GVariantIter *array;
3218     GVariantIter tuple;
3219     const gchar **strv;
3220     gchar **my_strv;
3221     GVariant *value;
3222     gchar *str;
3223     gsize i;
3224 
3225     g_variant_builder_init (&builder, G_VARIANT_TYPE ("aaay"));
3226     g_variant_builder_add (&builder, "^aay", strvector);
3227     g_variant_builder_add (&builder, "^aay", strvector);
3228     g_variant_builder_add (&builder, "^aay", strvector);
3229     value = g_variant_new ("aaay", &builder);
3230     array = g_variant_iter_new (value);
3231     i = 0;
3232     while (g_variant_iter_loop (array, "^aay", &my_strv))
3233       i++;
3234     g_assert_cmpuint (i, ==, 3);
3235 
3236     /* start over */
3237     g_variant_iter_init (array, value);
3238     i = 0;
3239     while (g_variant_iter_loop (array, "^a&ay", &strv))
3240       i++;
3241     g_assert_cmpuint (i, ==, 3);
3242     g_variant_unref (value);
3243     g_variant_iter_free (array);
3244 
3245     /* next test */
3246     g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
3247     g_variant_builder_add (&builder, "^ay", test_strs[0]);
3248     g_variant_builder_add (&builder, "^ay", test_strs[1]);
3249     g_variant_builder_add (&builder, "^ay", test_strs[2]);
3250     value = g_variant_new ("(aay^aay^a&ay)", &builder, strvector, strvector);
3251     g_variant_iter_init (&tuple, value);
3252     g_variant_iter_next (&tuple, "aay", &array);
3253 
3254     i = 0;
3255     while (g_variant_iter_loop (array, "^ay", &str))
3256       g_assert_cmpstr (str, ==, test_strs[i++]);
3257     g_assert_cmpuint (i, ==, 3);
3258 
3259     g_variant_iter_free (array);
3260 
3261     /* start over */
3262     g_variant_iter_init (&tuple, value);
3263     g_variant_iter_next (&tuple, "aay", &array);
3264 
3265     i = 0;
3266     while (g_variant_iter_loop (array, "^&ay", &str))
3267       g_assert_cmpstr (str, ==, test_strs[i++]);
3268     g_assert_cmpuint (i, ==, 3);
3269 
3270     g_variant_iter_free (array);
3271 
3272     g_variant_iter_next (&tuple, "^a&ay", &strv);
3273     g_variant_iter_next (&tuple, "^aay", &my_strv);
3274 
3275     g_assert_cmpstrv (strv, strvector);
3276     g_assert_cmpstrv (my_strv, strvector);
3277 
3278     g_variant_unref (value);
3279     g_strfreev (my_strv);
3280     g_free (strv);
3281   }
3282 
3283   {
3284     const gchar *strvector[] = {"/hello", "/world", NULL};
3285     const gchar *test_strs[] = {"/foo", "/bar", "/baz" };
3286     GVariantBuilder builder;
3287     GVariantIter *array;
3288     GVariantIter tuple;
3289     const gchar **strv;
3290     gchar **my_strv;
3291     GVariant *value;
3292     gchar *str;
3293     gsize i;
3294 
3295     g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY);
3296     g_variant_builder_add (&builder, "o", test_strs[0]);
3297     g_variant_builder_add (&builder, "o", test_strs[1]);
3298     g_variant_builder_add (&builder, "o", test_strs[2]);
3299     value = g_variant_new ("(ao^ao^a&o)", &builder, strvector, strvector);
3300     g_variant_iter_init (&tuple, value);
3301     g_variant_iter_next (&tuple, "ao", &array);
3302 
3303     i = 0;
3304     while (g_variant_iter_loop (array, "o", &str))
3305       g_assert_cmpstr (str, ==, test_strs[i++]);
3306     g_assert_cmpuint (i, ==, 3);
3307 
3308     g_variant_iter_free (array);
3309 
3310     /* start over */
3311     g_variant_iter_init (&tuple, value);
3312     g_variant_iter_next (&tuple, "ao", &array);
3313 
3314     i = 0;
3315     while (g_variant_iter_loop (array, "&o", &str))
3316       g_assert_cmpstr (str, ==, test_strs[i++]);
3317     g_assert_cmpuint (i, ==, 3);
3318 
3319     g_variant_iter_free (array);
3320 
3321     g_variant_iter_next (&tuple, "^a&o", &strv);
3322     g_variant_iter_next (&tuple, "^ao", &my_strv);
3323 
3324     g_assert_cmpstrv (strv, strvector);
3325     g_assert_cmpstrv (my_strv, strvector);
3326 
3327     g_variant_unref (value);
3328     g_strfreev (my_strv);
3329     g_free (strv);
3330   }
3331 
3332   {
3333     const gchar *strvector[] = { "i", "ii", "iii", "iv", "v", "vi", NULL };
3334     GVariantBuilder builder;
3335     GVariantIter iter;
3336     GVariantIter *i2;
3337     GVariantIter *i3;
3338     GVariant *value;
3339     GVariant *sub;
3340     gchar **strv;
3341     gsize i;
3342 
3343     g_variant_builder_init (&builder, G_VARIANT_TYPE ("aas"));
3344     g_variant_builder_open (&builder, G_VARIANT_TYPE ("as"));
3345     for (i = 0; i < 6; i++)
3346       if (i & 1)
3347         g_variant_builder_add (&builder, "s", strvector[i]);
3348       else
3349         g_variant_builder_add (&builder, "&s", strvector[i]);
3350     g_variant_builder_close (&builder);
3351     g_variant_builder_add (&builder, "^as", strvector);
3352     g_variant_builder_add (&builder, "^as", strvector);
3353     value = g_variant_new ("aas", &builder);
3354 
3355     g_variant_iter_init (&iter, value);
3356     while (g_variant_iter_loop (&iter, "^as", &strv))
3357       for (i = 0; i < 6; i++)
3358         g_assert_cmpstr (strv[i], ==, strvector[i]);
3359 
3360     g_variant_iter_init (&iter, value);
3361     while (g_variant_iter_loop (&iter, "^a&s", &strv))
3362       for (i = 0; i < 6; i++)
3363         g_assert_cmpstr (strv[i], ==, strvector[i]);
3364 
3365     g_variant_iter_init (&iter, value);
3366     while (g_variant_iter_loop (&iter, "as", &i2))
3367       {
3368         gchar *str;
3369 
3370         i = 0;
3371         while (g_variant_iter_loop (i2, "s", &str))
3372           g_assert_cmpstr (str, ==, strvector[i++]);
3373         g_assert_cmpuint (i, ==, 6);
3374       }
3375 
3376     g_variant_iter_init (&iter, value);
3377     i3 = g_variant_iter_copy (&iter);
3378     while (g_variant_iter_loop (&iter, "@as", &sub))
3379       {
3380         gchar *str = g_variant_print (sub, TRUE);
3381         g_assert_cmpstr (str, ==,
3382                          "['i', 'ii', 'iii', 'iv', 'v', 'vi']");
3383         g_free (str);
3384       }
3385 
3386     g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
3387                            "*NULL has already been returned*");
3388     g_variant_iter_next_value (&iter);
3389     g_test_assert_expected_messages ();
3390 
3391     while (g_variant_iter_loop (i3, "*", &sub))
3392       {
3393         gchar *str = g_variant_print (sub, TRUE);
3394         g_assert_cmpstr (str, ==,
3395                          "['i', 'ii', 'iii', 'iv', 'v', 'vi']");
3396         g_free (str);
3397       }
3398 
3399     g_variant_iter_free (i3);
3400 
3401     for (i = 0; i < g_variant_n_children (value); i++)
3402       {
3403         gsize j;
3404 
3405         g_variant_get_child (value, i, "*", &sub);
3406 
3407         for (j = 0; j < g_variant_n_children (sub); j++)
3408           {
3409             const gchar *str = NULL;
3410             GVariant *cval;
3411 
3412             g_variant_get_child (sub, j, "&s", &str);
3413             g_assert_cmpstr (str, ==, strvector[j]);
3414 
3415             cval = g_variant_get_child_value (sub, j);
3416             g_variant_get (cval, "&s", &str);
3417             g_assert_cmpstr (str, ==, strvector[j]);
3418             g_variant_unref (cval);
3419           }
3420 
3421         g_variant_unref (sub);
3422       }
3423 
3424     g_variant_unref (value);
3425   }
3426 
3427   {
3428     gboolean justs[10];
3429     GVariant *value;
3430 
3431     GVariant *vval;
3432     guchar byteval;
3433     gboolean bval;
3434     gint16 i16val;
3435     guint16 u16val;
3436     gint32 i32val;
3437     guint32 u32val;
3438     gint64 i64val;
3439     guint64 u64val;
3440     gdouble dval;
3441     gint32 hval;
3442 
3443     /* test all 'nothing' */
3444     value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
3445                            FALSE, 'a',
3446                            FALSE, TRUE,
3447                            FALSE, (gint16) 123,
3448                            FALSE, (guint16) 123,
3449                            FALSE, (gint32) 123,
3450                            FALSE, (guint32) 123,
3451                            FALSE, (gint64) 123,
3452                            FALSE, (guint64) 123,
3453                            FALSE, (gint32) -1,
3454                            FALSE, (gdouble) 37.5,
3455                            NULL);
3456 
3457     /* both NULL */
3458     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3459                    NULL, NULL,
3460                    NULL, NULL,
3461                    NULL, NULL,
3462                    NULL, NULL,
3463                    NULL, NULL,
3464                    NULL, NULL,
3465                    NULL, NULL,
3466                    NULL, NULL,
3467                    NULL, NULL,
3468                    NULL, NULL,
3469                    NULL);
3470 
3471     /* NULL values */
3472     memset (justs, 1, sizeof justs);
3473     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3474                    &justs[0], NULL,
3475                    &justs[1], NULL,
3476                    &justs[2], NULL,
3477                    &justs[3], NULL,
3478                    &justs[4], NULL,
3479                    &justs[5], NULL,
3480                    &justs[6], NULL,
3481                    &justs[7], NULL,
3482                    &justs[8], NULL,
3483                    &justs[9], NULL,
3484                    NULL);
3485     g_assert_true (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] ||
3486                      justs[5] || justs[6] || justs[7] || justs[8] || justs[9]));
3487 
3488     /* both non-NULL */
3489     memset (justs, 1, sizeof justs);
3490     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3491     vval = (void *) 1;
3492     bval = TRUE;
3493     dval = 88.88;
3494     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3495                    &justs[0], &byteval,
3496                    &justs[1], &bval,
3497                    &justs[2], &i16val,
3498                    &justs[3], &u16val,
3499                    &justs[4], &i32val,
3500                    &justs[5], &u32val,
3501                    &justs[6], &i64val,
3502                    &justs[7], &u64val,
3503                    &justs[8], &hval,
3504                    &justs[9], &dval,
3505                    &vval);
3506     g_assert_true (!(justs[0] || justs[1] || justs[2] || justs[3] || justs[4] ||
3507                      justs[5] || justs[6] || justs[7] || justs[8] || justs[9]));
3508     g_assert_true (byteval == '\0' && bval == FALSE);
3509     g_assert_true (i16val == 0 && u16val == 0 && i32val == 0 &&
3510                    u32val == 0 && i64val == 0 && u64val == 0 &&
3511                    hval == 0 && dval == 0.0);
3512     g_assert_null (vval);
3513 
3514     /* NULL justs */
3515     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3516     vval = (void *) 1;
3517     bval = TRUE;
3518     dval = 88.88;
3519     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3520                    NULL, &byteval,
3521                    NULL, &bval,
3522                    NULL, &i16val,
3523                    NULL, &u16val,
3524                    NULL, &i32val,
3525                    NULL, &u32val,
3526                    NULL, &i64val,
3527                    NULL, &u64val,
3528                    NULL, &hval,
3529                    NULL, &dval,
3530                    &vval);
3531     g_assert_true (byteval == '\0' && bval == FALSE);
3532     g_assert_true (i16val == 0 && u16val == 0 && i32val == 0 &&
3533                    u32val == 0 && i64val == 0 && u64val == 0 &&
3534                    hval == 0 && dval == 0.0);
3535     g_assert_null (vval);
3536 
3537     g_variant_unref (value);
3538 
3539 
3540     /* test all 'just' */
3541     value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
3542                            TRUE, 'a',
3543                            TRUE, TRUE,
3544                            TRUE, (gint16) 123,
3545                            TRUE, (guint16) 123,
3546                            TRUE, (gint32) 123,
3547                            TRUE, (guint32) 123,
3548                            TRUE, (gint64) 123,
3549                            TRUE, (guint64) 123,
3550                            TRUE, (gint32) -1,
3551                            TRUE, (gdouble) 37.5,
3552                            g_variant_new ("()"));
3553 
3554     /* both NULL */
3555     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3556                    NULL, NULL,
3557                    NULL, NULL,
3558                    NULL, NULL,
3559                    NULL, NULL,
3560                    NULL, NULL,
3561                    NULL, NULL,
3562                    NULL, NULL,
3563                    NULL, NULL,
3564                    NULL, NULL,
3565                    NULL, NULL,
3566                    NULL);
3567 
3568     /* NULL values */
3569     memset (justs, 0, sizeof justs);
3570     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3571                    &justs[0], NULL,
3572                    &justs[1], NULL,
3573                    &justs[2], NULL,
3574                    &justs[3], NULL,
3575                    &justs[4], NULL,
3576                    &justs[5], NULL,
3577                    &justs[6], NULL,
3578                    &justs[7], NULL,
3579                    &justs[8], NULL,
3580                    &justs[9], NULL,
3581                    NULL);
3582     g_assert_true (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] &&
3583                    justs[5] && justs[6] && justs[7] && justs[8] && justs[9]);
3584 
3585     /* both non-NULL */
3586     memset (justs, 0, sizeof justs);
3587     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3588     vval = (void *) 1;
3589     bval = FALSE;
3590     dval = 88.88;
3591     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3592                    &justs[0], &byteval,
3593                    &justs[1], &bval,
3594                    &justs[2], &i16val,
3595                    &justs[3], &u16val,
3596                    &justs[4], &i32val,
3597                    &justs[5], &u32val,
3598                    &justs[6], &i64val,
3599                    &justs[7], &u64val,
3600                    &justs[8], &hval,
3601                    &justs[9], &dval,
3602                    &vval);
3603     g_assert_true (justs[0] && justs[1] && justs[2] && justs[3] && justs[4] &&
3604                    justs[5] && justs[6] && justs[7] && justs[8] && justs[9]);
3605     g_assert_true (byteval == 'a' && bval == TRUE);
3606     g_assert_true (i16val == 123 && u16val == 123 && i32val == 123 &&
3607                    u32val == 123 && i64val == 123 && u64val == 123 &&
3608                    hval == -1 && dval == 37.5);
3609     g_assert_true (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT));
3610     g_variant_unref (vval);
3611 
3612     /* NULL justs */
3613     byteval = i16val = u16val = i32val = u32val = i64val = u64val = hval = 88;
3614     vval = (void *) 1;
3615     bval = TRUE;
3616     dval = 88.88;
3617     g_variant_get (value, "(mymbmnmqmimumxmtmhmdmv)",
3618                    NULL, &byteval,
3619                    NULL, &bval,
3620                    NULL, &i16val,
3621                    NULL, &u16val,
3622                    NULL, &i32val,
3623                    NULL, &u32val,
3624                    NULL, &i64val,
3625                    NULL, &u64val,
3626                    NULL, &hval,
3627                    NULL, &dval,
3628                    &vval);
3629     g_assert_true (byteval == 'a' && bval == TRUE);
3630     g_assert_true (i16val == 123 && u16val == 123 && i32val == 123 &&
3631                    u32val == 123 && i64val == 123 && u64val == 123 &&
3632                    hval == -1 && dval == 37.5);
3633     g_assert_true (g_variant_is_of_type (vval, G_VARIANT_TYPE_UNIT));
3634     g_variant_unref (vval);
3635 
3636     g_variant_unref (value);
3637   }
3638 
3639   {
3640     GVariant *value;
3641     gchar *str;
3642 
3643     value = g_variant_new ("(masas)", NULL, NULL);
3644     g_variant_ref_sink (value);
3645 
3646     str = g_variant_print (value, TRUE);
3647     g_assert_cmpstr (str, ==, "(@mas nothing, @as [])");
3648     g_variant_unref (value);
3649     g_free (str);
3650 
3651     do_failed_test ("/gvariant/varargs/subprocess/empty-array",
3652                     "*which type of empty array*");
3653   }
3654 
3655   g_variant_type_info_assert_no_infos ();
3656 }
3657 
3658 static void
hash_get(GVariant * value,const gchar * format,...)3659 hash_get (GVariant    *value,
3660           const gchar *format,
3661           ...)
3662 {
3663   const gchar *endptr = NULL;
3664   gboolean hash;
3665   va_list ap;
3666 
3667   hash = g_str_has_suffix (format, "#");
3668 
3669   va_start (ap, format);
3670   g_variant_get_va (value, format, hash ? &endptr : NULL, &ap);
3671   va_end (ap);
3672 
3673   if (hash)
3674     g_assert_cmpint (*endptr, ==, '#');
3675 }
3676 
3677 static GVariant *
hash_new(const gchar * format,...)3678 hash_new (const gchar *format,
3679           ...)
3680 {
3681   const gchar *endptr = NULL;
3682   GVariant *value;
3683   gboolean hash;
3684   va_list ap;
3685 
3686   hash = g_str_has_suffix (format, "#");
3687 
3688   va_start (ap, format);
3689   value = g_variant_new_va (format, hash ? &endptr : NULL, &ap);
3690   va_end (ap);
3691 
3692   if (hash)
3693     g_assert_cmpint (*endptr, ==, '#');
3694 
3695   return value;
3696 }
3697 
3698 static void
test_valist(void)3699 test_valist (void)
3700 {
3701   GVariant *value;
3702   gint32 x;
3703 
3704   x = 0;
3705   value = hash_new ("i", 234);
3706   hash_get (value, "i", &x);
3707   g_assert_cmpint (x, ==, 234);
3708   g_variant_unref (value);
3709 
3710   x = 0;
3711   value = hash_new ("i#", 234);
3712   hash_get (value, "i#", &x);
3713   g_assert_cmpint (x, ==, 234);
3714   g_variant_unref (value);
3715 
3716   g_variant_type_info_assert_no_infos ();
3717 }
3718 
3719 static void
test_builder_memory(void)3720 test_builder_memory (void)
3721 {
3722   GVariantBuilder *hb;
3723   GVariantBuilder sb;
3724 
3725   hb = g_variant_builder_new  (G_VARIANT_TYPE_ARRAY);
3726   g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
3727   g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
3728   g_variant_builder_open (hb, G_VARIANT_TYPE_ARRAY);
3729   g_variant_builder_add (hb, "s", "some value");
3730   g_variant_builder_ref (hb);
3731   g_variant_builder_unref (hb);
3732   g_variant_builder_unref (hb);
3733 
3734   hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
3735   g_variant_builder_unref (hb);
3736 
3737   hb = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
3738   g_variant_builder_clear (hb);
3739   g_variant_builder_unref (hb);
3740 
3741   g_variant_builder_init (&sb, G_VARIANT_TYPE_ARRAY);
3742   g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY);
3743   g_variant_builder_open (&sb, G_VARIANT_TYPE_ARRAY);
3744   g_variant_builder_add (&sb, "s", "some value");
3745   g_variant_builder_clear (&sb);
3746 
3747   g_variant_type_info_assert_no_infos ();
3748 }
3749 
3750 static void
test_hashing(void)3751 test_hashing (void)
3752 {
3753   GVariant *items[4096];
3754   GHashTable *table;
3755   gsize i;
3756 
3757   table = g_hash_table_new_full (g_variant_hash, g_variant_equal,
3758                                  (GDestroyNotify ) g_variant_unref,
3759                                  NULL);
3760 
3761   for (i = 0; i < G_N_ELEMENTS (items); i++)
3762     {
3763       TreeInstance *tree;
3764       gsize j;
3765 
3766  again:
3767       tree = tree_instance_new (NULL, 0);
3768       items[i] = tree_instance_get_gvariant (tree);
3769       tree_instance_free (tree);
3770 
3771       for (j = 0; j < i; j++)
3772         if (g_variant_equal (items[i], items[j]))
3773           {
3774             g_variant_unref (items[i]);
3775             goto again;
3776           }
3777 
3778       g_hash_table_insert (table,
3779                            g_variant_ref_sink (items[i]),
3780                            GINT_TO_POINTER (i));
3781     }
3782 
3783   for (i = 0; i < G_N_ELEMENTS (items); i++)
3784     {
3785       gpointer result;
3786 
3787       result = g_hash_table_lookup (table, items[i]);
3788       g_assert_cmpint (GPOINTER_TO_INT (result), ==, i);
3789     }
3790 
3791   g_hash_table_unref (table);
3792 
3793   g_variant_type_info_assert_no_infos ();
3794 }
3795 
3796 static void
test_gv_byteswap(void)3797 test_gv_byteswap (void)
3798 {
3799 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
3800 # define native16(x)  x, 0
3801 # define swapped16(x) 0, x
3802 #else
3803 # define native16(x)  0, x
3804 # define swapped16(x) x, 0
3805 #endif
3806   /* all kinds of of crazy randomised testing already performed on the
3807    * byteswapper in the /gvariant/serialiser/byteswap test and all kinds
3808    * of crazy randomised testing performed against the serialiser
3809    * normalisation functions in the /gvariant/serialiser/fuzz/ tests.
3810    *
3811    * just test a few simple cases here to make sure they each work
3812    */
3813   guchar validbytes[] = { 'a', '\0', swapped16(66), 2,
3814                           0,
3815                           'b', '\0', swapped16(77), 2,
3816                           5, 11 };
3817   guchar corruptbytes[] = { 'a', '\0', swapped16(66), 2,
3818                             0,
3819                             'b', '\0', swapped16(77), 2,
3820                             6, 11 };
3821   guint valid_data[4], corrupt_data[4];
3822   GVariant *value, *swapped;
3823   gchar *string, *string2;
3824 
3825   memcpy (valid_data, validbytes, sizeof validbytes);
3826   memcpy (corrupt_data, corruptbytes, sizeof corruptbytes);
3827 
3828   /* trusted */
3829   value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"),
3830                                    valid_data, sizeof validbytes, TRUE,
3831                                    NULL, NULL);
3832   swapped = g_variant_byteswap (value);
3833   g_variant_unref (value);
3834   g_assert_cmpuint (g_variant_get_size (swapped), ==, 13);
3835   string = g_variant_print (swapped, FALSE);
3836   g_variant_unref (swapped);
3837   g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]");
3838   g_free (string);
3839 
3840   /* untrusted but valid */
3841   value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"),
3842                                    valid_data, sizeof validbytes, FALSE,
3843                                    NULL, NULL);
3844   swapped = g_variant_byteswap (value);
3845   g_variant_unref (value);
3846   g_assert_cmpuint (g_variant_get_size (swapped), ==, 13);
3847   string = g_variant_print (swapped, FALSE);
3848   g_variant_unref (swapped);
3849   g_assert_cmpstr (string, ==, "[('a', 66), ('b', 77)]");
3850   g_free (string);
3851 
3852   /* untrusted, invalid */
3853   value = g_variant_new_from_data (G_VARIANT_TYPE ("a(sn)"),
3854                                    corrupt_data, sizeof corruptbytes, FALSE,
3855                                    NULL, NULL);
3856   string = g_variant_print (value, FALSE);
3857   swapped = g_variant_byteswap (value);
3858   g_variant_unref (value);
3859   g_assert_cmpuint (g_variant_get_size (swapped), ==, 13);
3860   value = g_variant_byteswap (swapped);
3861   g_variant_unref (swapped);
3862   string2 = g_variant_print (value, FALSE);
3863   g_assert_cmpuint (g_variant_get_size (value), ==, 13);
3864   g_variant_unref (value);
3865   g_assert_cmpstr (string, ==, string2);
3866   g_free (string2);
3867   g_free (string);
3868 }
3869 
3870 static void
test_gv_byteswap_non_normal_non_aligned(void)3871 test_gv_byteswap_non_normal_non_aligned (void)
3872 {
3873   const guint8 data[] = { 0x02 };
3874   GVariant *v = NULL;
3875   GVariant *v_byteswapped = NULL;
3876 
3877   g_test_summary ("Test that calling g_variant_byteswap() on a variant which "
3878                   "is in non-normal form and doesn’t need byteswapping returns "
3879                   "the same variant in normal form.");
3880 
3881   v = g_variant_new_from_data (G_VARIANT_TYPE_BOOLEAN, data, sizeof (data), FALSE, NULL, NULL);
3882   g_assert_false (g_variant_is_normal_form (v));
3883 
3884   v_byteswapped = g_variant_byteswap (v);
3885   g_assert_true (g_variant_is_normal_form (v_byteswapped));
3886 
3887   g_assert_cmpvariant (v, v_byteswapped);
3888 
3889   g_variant_unref (v);
3890   g_variant_unref (v_byteswapped);
3891 }
3892 
3893 static void
test_parser(void)3894 test_parser (void)
3895 {
3896   TreeInstance *tree;
3897   GVariant *parsed;
3898   GVariant *value;
3899   gchar *pt, *p;
3900   gchar *res;
3901 
3902   tree = tree_instance_new (NULL, 3);
3903   value = tree_instance_get_gvariant (tree);
3904   tree_instance_free (tree);
3905 
3906   pt = g_variant_print (value, TRUE);
3907   p = g_variant_print (value, FALSE);
3908 
3909   parsed = g_variant_parse (NULL, pt, NULL, NULL, NULL);
3910   res = g_variant_print (parsed, FALSE);
3911   g_assert_cmpstr (p, ==, res);
3912   g_variant_unref (parsed);
3913   g_free (res);
3914 
3915   parsed = g_variant_parse (g_variant_get_type (value), p,
3916                             NULL, NULL, NULL);
3917   res = g_variant_print (parsed, TRUE);
3918   g_assert_cmpstr (pt, ==, res);
3919   g_variant_unref (parsed);
3920   g_free (res);
3921 
3922   g_variant_unref (value);
3923   g_free (pt);
3924   g_free (p);
3925 }
3926 
3927 static void
test_parses(void)3928 test_parses (void)
3929 {
3930   gsize i;
3931 
3932   for (i = 0; i < 100; i++)
3933     {
3934       test_parser ();
3935     }
3936 
3937   /* mini test */
3938   {
3939     GError *error = NULL;
3940     gchar str[128];
3941     GVariant *val;
3942     gchar *p, *p2;
3943 
3944     for (i = 0; i < 127; i++)
3945       str[i] = i + 1;
3946     str[i] = 0;
3947 
3948     val = g_variant_new_string (str);
3949     p = g_variant_print (val, FALSE);
3950     g_variant_unref (val);
3951 
3952     val = g_variant_parse (NULL, p, NULL, NULL, &error);
3953     p2 = g_variant_print (val, FALSE);
3954 
3955     g_assert_cmpstr (str, ==, g_variant_get_string (val, NULL));
3956     g_assert_cmpstr (p, ==, p2);
3957 
3958     g_variant_unref (val);
3959     g_free (p2);
3960     g_free (p);
3961   }
3962 
3963   /* another mini test */
3964   {
3965     const gchar *end;
3966     GVariant *value;
3967 
3968     value = g_variant_parse (G_VARIANT_TYPE_INT32, "1 2 3", NULL, &end, NULL);
3969     g_assert_cmpint (g_variant_get_int32 (value), ==, 1);
3970     /* make sure endptr returning works */
3971     g_assert_cmpstr (end, ==, " 2 3");
3972     g_variant_unref (value);
3973   }
3974 
3975   /* unicode mini test */
3976   {
3977     /* ał�� */
3978     const gchar orig[] = "a\xc5\x82\xf0\x9d\x84\x9e \t\n";
3979     GVariant *value;
3980     gchar *printed;
3981 
3982     value = g_variant_new_string (orig);
3983     printed = g_variant_print (value, FALSE);
3984     g_variant_unref (value);
3985 
3986     g_assert_cmpstr (printed, ==, "'a\xc5\x82\xf0\x9d\x84\x9e \\t\\n'");
3987     value = g_variant_parse (NULL, printed, NULL, NULL, NULL);
3988     g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig);
3989     g_variant_unref (value);
3990     g_free (printed);
3991   }
3992 
3993   /* escapes */
3994   {
3995     const gchar orig[] = " \342\200\254 \360\220\210\240 \a \b \f \n \r \t \v ";
3996     GVariant *value;
3997     gchar *printed;
3998 
3999     value = g_variant_new_string (orig);
4000     printed = g_variant_print (value, FALSE);
4001     g_variant_unref (value);
4002 
4003     g_assert_cmpstr (printed, ==, "' \\u202c \\U00010220 \\a \\b \\f \\n \\r \\t \\v '");
4004     value = g_variant_parse (NULL, printed, NULL, NULL, NULL);
4005     g_assert_cmpstr (g_variant_get_string (value, NULL), ==, orig);
4006     g_variant_unref (value);
4007     g_free (printed);
4008   }
4009 
4010   /* pattern coalese of `MN` and `*` is `MN` */
4011   {
4012     GVariant *value = NULL;
4013     GError *error = NULL;
4014 
4015     value = g_variant_parse (NULL, "[[0], [], [nothing]]", NULL, NULL, &error);
4016     g_assert_no_error (error);
4017     g_assert_cmpstr (g_variant_get_type_string (value), ==, "aami");
4018     g_variant_unref (value);
4019   }
4020 
4021 #ifndef _MSC_VER
4022   /* inf/nan strings are C99 features which Visual C++ does not support */
4023   /* inf/nan mini test */
4024   {
4025     const gchar *tests[] = { "inf", "-inf", "nan" };
4026     GVariant *value;
4027     gchar *printed;
4028     gchar *printed_down;
4029     gsize i;
4030 
4031     for (i = 0; i < G_N_ELEMENTS (tests); i++)
4032       {
4033         GError *error = NULL;
4034         value = g_variant_parse (NULL, tests[i], NULL, NULL, &error);
4035         printed = g_variant_print (value, FALSE);
4036         /* Canonicalize to lowercase; https://bugzilla.gnome.org/show_bug.cgi?id=704585 */
4037         printed_down = g_ascii_strdown (printed, -1);
4038         g_assert_true (g_str_has_prefix (printed_down, tests[i]));
4039         g_free (printed);
4040         g_free (printed_down);
4041         g_variant_unref (value);
4042       }
4043   }
4044 #endif
4045 
4046   g_variant_type_info_assert_no_infos ();
4047 }
4048 
4049 static void
test_parse_failures(void)4050 test_parse_failures (void)
4051 {
4052   const gchar *test[] = {
4053     "[1, 2,",                   "6:",              "expected value",
4054     "",                         "0:",              "expected value",
4055     "(1, 2,",                   "6:",              "expected value",
4056     "<1",                       "2:",              "expected '>'",
4057     "[]",                       "0-2:",            "unable to infer",
4058     "(,",                       "1:",              "expected value",
4059     "[4,'']",                   "1-2,3-5:",        "common type",
4060     "[4, '', 5]",               "1-2,4-6:",        "common type",
4061     "['', 4, 5]",               "1-3,5-6:",        "common type",
4062     "[4, 5, '']",               "1-2,7-9:",        "common type",
4063     "[[4], [], ['']]",          "1-4,10-14:",      "common type",
4064     "[[], [4], ['']]",          "5-8,10-14:",      "common type",
4065     "just",                     "4:",              "expected value",
4066     "nothing",                  "0-7:",            "unable to infer",
4067     "just [4, '']",             "6-7,9-11:",       "common type",
4068     "[[4,'']]",                 "2-3,4-6:",        "common type",
4069     "([4,''],)",                "2-3,4-6:",        "common type",
4070     "(4)",                      "2:",              "','",
4071     "{}",                       "0-2:",            "unable to infer",
4072     "{[1,2],[3,4]}",            "0-13:",           "basic types",
4073     "{[1,2]:[3,4]}",            "0-13:",           "basic types",
4074     "justt",                    "0-5:",            "unknown keyword",
4075     "nothng",                   "0-6:",            "unknown keyword",
4076     "uint33",                   "0-6:",            "unknown keyword",
4077     "@mi just ''",              "9-11:",           "can not parse as",
4078     "@ai ['']",                 "5-7:",            "can not parse as",
4079     "@(i) ('',)",               "6-8:",            "can not parse as",
4080     "[[], 5]",                  "1-3,5-6:",        "common type",
4081     "[[5], 5]",                 "1-4,6-7:",        "common type",
4082     "5 5",                      "2:",              "expected end of input",
4083     "[5, [5, '']]",             "5-6,8-10:",       "common type",
4084     "@i just 5",                "3-9:",            "can not parse as",
4085     "@i nothing",               "3-10:",           "can not parse as",
4086     "@i []",                    "3-5:",            "can not parse as",
4087     "@i ()",                    "3-5:",            "can not parse as",
4088     "@ai (4,)",                 "4-8:",            "can not parse as",
4089     "@(i) []",                  "5-7:",            "can not parse as",
4090     "(5 5)",                    "3:",              "expected ','",
4091     "[5 5]",                    "3:",              "expected ',' or ']'",
4092     "(5, 5 5)",                 "6:",              "expected ',' or ')'",
4093     "[5, 5 5]",                 "6:",              "expected ',' or ']'",
4094     "<@i []>",                  "4-6:",            "can not parse as",
4095     "<[5 5]>",                  "4:",              "expected ',' or ']'",
4096     "{[4,''],5}",               "2-3,4-6:",        "common type",
4097     "{5,[4,'']}",               "4-5,6-8:",        "common type",
4098     "@i {1,2}",                 "3-8:",            "can not parse as",
4099     "{@i '', 5}",               "4-6:",            "can not parse as",
4100     "{5, @i ''}",               "7-9:",            "can not parse as",
4101     "@ai {}",                   "4-6:",            "can not parse as",
4102     "{@i '': 5}",               "4-6:",            "can not parse as",
4103     "{5: @i ''}",               "7-9:",            "can not parse as",
4104     "{<4,5}",                   "3:",              "expected '>'",
4105     "{4,<5}",                   "5:",              "expected '>'",
4106     "{4,5,6}",                  "4:",              "expected '}'",
4107     "{5 5}",                    "3:",              "expected ':' or ','",
4108     "{4: 5: 6}",                "5:",              "expected ',' or '}'",
4109     "{4:5,<6:7}",               "7:",              "expected '>'",
4110     "{4:5,6:<7}",               "9:",              "expected '>'",
4111     "{4:5,6 7}",                "7:",              "expected ':'",
4112     "@o 'foo'",                 "3-8:",            "object path",
4113     "@g 'zzz'",                 "3-8:",            "signature",
4114     "@i true",                  "3-7:",            "can not parse as",
4115     "@z 4",                     "0-2:",            "invalid type",
4116     "@a* []",                   "0-3:",            "definite",
4117     "@ai [3 3]",                "7:",              "expected ',' or ']'",
4118     "18446744073709551616",     "0-20:",           "too big for any type",
4119     "-18446744073709551616",    "0-21:",           "too big for any type",
4120     "byte 256",                 "5-8:",            "out of range for type",
4121     "byte -1",                  "5-7:",            "out of range for type",
4122     "int16 32768",              "6-11:",           "out of range for type",
4123     "int16 -32769",             "6-12:",           "out of range for type",
4124     "uint16 -1",                "7-9:",            "out of range for type",
4125     "uint16 65536",             "7-12:",           "out of range for type",
4126     "2147483648",               "0-10:",           "out of range for type",
4127     "-2147483649",              "0-11:",           "out of range for type",
4128     "uint32 -1",                "7-9:",            "out of range for type",
4129     "uint32 4294967296",        "7-17:",           "out of range for type",
4130     "@x 9223372036854775808",   "3-22:",           "out of range for type",
4131     "@x -9223372036854775809",  "3-23:",           "out of range for type",
4132     "@t -1",                    "3-5:",            "out of range for type",
4133     "@t 18446744073709551616",  "3-23:",           "too big for any type",
4134     "handle 2147483648",        "7-17:",           "out of range for type",
4135     "handle -2147483649",       "7-18:",           "out of range for type",
4136     "1.798e308",                "0-9:",            "too big for any type",
4137     "37.5a488",                 "4-5:",            "invalid character",
4138     "0x7ffgf",                  "5-6:",            "invalid character",
4139     "07758",                    "4-5:",            "invalid character",
4140     "123a5",                    "3-4:",            "invalid character",
4141     "@ai 123",                  "4-7:",            "can not parse as",
4142     "'\"\\'",                   "0-4:",            "unterminated string",
4143     "'\"\\'\\",                 "0-5:",            "unterminated string",
4144     "boolean 4",                "8-9:",            "can not parse as",
4145     "int32 true",               "6-10:",           "can not parse as",
4146     "[double 5, int32 5]",      "1-9,11-18:",      "common type",
4147     "string 4",                 "7-8:",            "can not parse as",
4148     "\x0a",                     "1:",              "expected value",
4149     "((",                       "2:",              "expected value",
4150     "(b",                       "1:",              "expected value",
4151     "b'",                       "0-2:",            "unterminated string constant",
4152     "b\"",                      "0-2:",            "unterminated string constant",
4153     "b'a",                      "0-3:",            "unterminated string constant",
4154     "b\"a",                     "0-3:",            "unterminated string constant",
4155     "b'\\",                     "0-3:",            "unterminated string constant",
4156     "b\"\\",                    "0-3:",            "unterminated string constant",
4157     "b'\\'",                    "0-4:",            "unterminated string constant",
4158     "b\"\\\"",                  "0-4:",            "unterminated string constant",
4159     "b'\\'a",                   "0-5:",            "unterminated string constant",
4160     "b\"\\\"a",                 "0-5:",            "unterminated string constant",
4161     "'\\u-ff4'",                "3:",              "invalid 4-character unicode escape",
4162     "'\\u+ff4'",                "3:",              "invalid 4-character unicode escape",
4163     "'\\u'",                    "3:",              "invalid 4-character unicode escape",
4164     "'\\u0'",                   "3-4:",            "invalid 4-character unicode escape",
4165     "'\\uHELLO'",               "3:",              "invalid 4-character unicode escape",
4166     "'\\u ff4'",                "3:",              "invalid 4-character unicode escape",
4167     "'\\u012'",                 "3-6:",            "invalid 4-character unicode escape",
4168     "'\\u0xff4'",               "3-4:",            "invalid 4-character unicode escape",
4169     "'\\U-ff4'",                "3:",              "invalid 8-character unicode escape",
4170     "'\\U+ff4'",                "3:",              "invalid 8-character unicode escape",
4171     "'\\U'",                    "3:",              "invalid 8-character unicode escape",
4172     "'\\U0'",                   "3-4:",            "invalid 8-character unicode escape",
4173     "'\\UHELLO'",               "3:",              "invalid 8-character unicode escape",
4174     "'\\U ff4'",                "3:",              "invalid 8-character unicode escape",
4175     "'\\U0123456'",             "3-10:",           "invalid 8-character unicode escape",
4176     "'\\U0xff4'",               "3-4:",            "invalid 8-character unicode escape",
4177   };
4178   guint i;
4179 
4180   for (i = 0; i < G_N_ELEMENTS (test); i += 3)
4181     {
4182       GError *error1 = NULL, *error2 = NULL;
4183       GVariant *value;
4184 
4185       /* Copy the test string and drop its nul terminator, then use the @limit
4186        * parameter of g_variant_parse() to set the length. This allows valgrind
4187        * to catch 1-byte heap buffer overflows. */
4188       gsize test_len = MAX (strlen (test[i]), 1);
4189       gchar *test_blob = g_malloc0 (test_len);  /* no nul terminator */
4190 
4191       memcpy (test_blob, test[i], test_len);
4192       value = g_variant_parse (NULL, test_blob, test_blob + test_len, NULL, &error1);
4193       g_assert_null (value);
4194 
4195       g_free (test_blob);
4196 
4197       if (!strstr (error1->message, test[i+2]))
4198         g_error ("test %u: Can't find '%s' in '%s'", i / 3,
4199                  test[i+2], error1->message);
4200 
4201       if (!g_str_has_prefix (error1->message, test[i+1]))
4202         g_error ("test %u: Expected location '%s' in '%s'", i / 3,
4203                  test[i+1], error1->message);
4204 
4205       /* Test again with the nul terminator this time. The behaviour should be
4206        * the same. */
4207       value = g_variant_parse (NULL, test[i], NULL, NULL, &error2);
4208       g_assert_null (value);
4209 
4210       g_assert_cmpint (error1->domain, ==, error2->domain);
4211       g_assert_cmpint (error1->code, ==, error2->code);
4212       g_assert_cmpstr (error1->message, ==, error2->message);
4213 
4214       g_clear_error (&error1);
4215       g_clear_error (&error2);
4216     }
4217 }
4218 
4219 /* Test that parsing GVariant text format integers works at the boundaries of
4220  * those integer types. We’re especially interested in the handling of the most
4221  * negative numbers, since those can’t be represented in sign + absolute value
4222  * form. */
4223 static void
test_parser_integer_bounds(void)4224 test_parser_integer_bounds (void)
4225 {
4226   GVariant *value = NULL;
4227   GError *local_error = NULL;
4228 
4229 #define test_bound(TYPE, type, text, expected_value) \
4230   value = g_variant_parse (G_VARIANT_TYPE_##TYPE, text, NULL, NULL, &local_error); \
4231   g_assert_no_error (local_error); \
4232   g_assert_nonnull (value); \
4233   g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE_##TYPE)); \
4234   g_assert_cmpint (g_variant_get_##type (value), ==, expected_value); \
4235   g_variant_unref (value)
4236 
4237   test_bound (BYTE, byte, "0", 0);
4238   test_bound (BYTE, byte, "255", G_MAXUINT8);
4239   test_bound (INT16, int16, "-32768", G_MININT16);
4240   test_bound (INT16, int16, "32767", G_MAXINT16);
4241   test_bound (INT32, int32, "-2147483648", G_MININT32);
4242   test_bound (INT32, int32, "2147483647", G_MAXINT32);
4243   test_bound (INT64, int64, "-9223372036854775808", G_MININT64);
4244   test_bound (INT64, int64, "9223372036854775807", G_MAXINT64);
4245   test_bound (HANDLE, handle, "-2147483648", G_MININT32);
4246   test_bound (HANDLE, handle, "2147483647", G_MAXINT32);
4247 
4248 #undef test_bound
4249 }
4250 
4251 /* Test that #GVariants which recurse too deeply are rejected. */
4252 static void
test_parser_recursion(void)4253 test_parser_recursion (void)
4254 {
4255   GVariant *value = NULL;
4256   GError *local_error = NULL;
4257   const guint recursion_depth = G_VARIANT_MAX_RECURSION_DEPTH + 1;
4258   gchar *silly_dict = g_malloc0 (recursion_depth * 2 + 1);
4259   gsize i;
4260 
4261   for (i = 0; i < recursion_depth; i++)
4262     {
4263       silly_dict[i] = '{';
4264       silly_dict[recursion_depth * 2 - i - 1] = '}';
4265     }
4266 
4267   value = g_variant_parse (NULL, silly_dict, NULL, NULL, &local_error);
4268   g_assert_error (local_error, G_VARIANT_PARSE_ERROR, G_VARIANT_PARSE_ERROR_RECURSION);
4269   g_assert_null (value);
4270   g_error_free (local_error);
4271   g_free (silly_dict);
4272 }
4273 
4274 static void
test_parse_bad_format_char(void)4275 test_parse_bad_format_char (void)
4276 {
4277   g_variant_new_parsed ("%z");
4278 
4279   g_assert_not_reached ();
4280 }
4281 
4282 static void
test_parse_bad_format_string(void)4283 test_parse_bad_format_string (void)
4284 {
4285   g_variant_new_parsed ("uint32 %i", 2);
4286 
4287   g_assert_not_reached ();
4288 }
4289 
4290 static void
test_parse_bad_args(void)4291 test_parse_bad_args (void)
4292 {
4293   g_variant_new_parsed ("%@i", g_variant_new_uint32 (2));
4294 
4295   g_assert_not_reached ();
4296 }
4297 
4298 static void
test_parse_positional(void)4299 test_parse_positional (void)
4300 {
4301   GVariant *value;
4302   check_and_free (g_variant_new_parsed ("[('one', 1), (%s, 2),"
4303                                         " ('three', %i)]", "two", 3),
4304                   "[('one', 1), ('two', 2), ('three', 3)]");
4305   value = g_variant_new_parsed ("[('one', 1), (%s, 2),"
4306                                 " ('three', %u)]", "two", 3);
4307   g_assert_true (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(su)")));
4308   check_and_free (value, "[('one', 1), ('two', 2), ('three', 3)]");
4309   check_and_free (g_variant_new_parsed ("{%s:%i}", "one", 1), "{'one': 1}");
4310 
4311   if (g_test_undefined ())
4312     {
4313       do_failed_test ("/gvariant/parse/subprocess/bad-format-char",
4314                       "*GVariant format string*");
4315 
4316       do_failed_test ("/gvariant/parse/subprocess/bad-format-string",
4317                       "*can not parse as*");
4318 
4319       do_failed_test ("/gvariant/parse/subprocess/bad-args",
4320                       "*expected GVariant of type 'i'*");
4321     }
4322 }
4323 
4324 static void
test_floating(void)4325 test_floating (void)
4326 {
4327   GVariant *value;
4328 
4329   value = g_variant_new_int32 (42);
4330   g_assert_true (g_variant_is_floating (value));
4331   g_variant_ref_sink (value);
4332   g_assert_true (!g_variant_is_floating (value));
4333   g_variant_unref (value);
4334 }
4335 
4336 static void
test_bytestring(void)4337 test_bytestring (void)
4338 {
4339   const gchar *test_string = "foo,bar,baz,quux,\xffoooo";
4340   GVariant *value;
4341   gchar **strv;
4342   gchar *str;
4343   const gchar *const_str;
4344   GVariant *untrusted_empty;
4345 
4346   strv = g_strsplit (test_string, ",", 0);
4347 
4348   value = g_variant_new_bytestring_array ((const gchar **) strv, -1);
4349   g_assert_true (g_variant_is_floating (value));
4350   g_strfreev (strv);
4351 
4352   str = g_variant_print (value, FALSE);
4353   g_variant_unref (value);
4354 
4355   value = g_variant_parse (NULL, str, NULL, NULL, NULL);
4356   g_free (str);
4357 
4358   strv = g_variant_dup_bytestring_array (value, NULL);
4359   g_variant_unref (value);
4360 
4361   str = g_strjoinv (",", strv);
4362   g_strfreev (strv);
4363 
4364   g_assert_cmpstr (str, ==, test_string);
4365   g_free (str);
4366 
4367   strv = g_strsplit (test_string, ",", 0);
4368   value = g_variant_new ("(^aay^a&ay^ay^&ay)",
4369                          strv, strv, strv[0], strv[0]);
4370   g_strfreev (strv);
4371 
4372   g_variant_get_child (value, 0, "^a&ay", &strv);
4373   str = g_strjoinv (",", strv);
4374   g_free (strv);
4375   g_assert_cmpstr (str, ==, test_string);
4376   g_free (str);
4377 
4378   g_variant_get_child (value, 0, "^aay", &strv);
4379   str = g_strjoinv (",", strv);
4380   g_strfreev (strv);
4381   g_assert_cmpstr (str, ==, test_string);
4382   g_free (str);
4383 
4384   g_variant_get_child (value, 1, "^a&ay", &strv);
4385   str = g_strjoinv (",", strv);
4386   g_free (strv);
4387   g_assert_cmpstr (str, ==, test_string);
4388   g_free (str);
4389 
4390   g_variant_get_child (value, 1, "^aay", &strv);
4391   str = g_strjoinv (",", strv);
4392   g_strfreev (strv);
4393   g_assert_cmpstr (str, ==, test_string);
4394   g_free (str);
4395 
4396   g_variant_get_child (value, 2, "^ay", &str);
4397   g_assert_cmpstr (str, ==, "foo");
4398   g_free (str);
4399 
4400   g_variant_get_child (value, 2, "^&ay", &str);
4401   g_assert_cmpstr (str, ==, "foo");
4402 
4403   g_variant_get_child (value, 3, "^ay", &str);
4404   g_assert_cmpstr (str, ==, "foo");
4405   g_free (str);
4406 
4407   g_variant_get_child (value, 3, "^&ay", &str);
4408   g_assert_cmpstr (str, ==, "foo");
4409   g_variant_unref (value);
4410 
4411   untrusted_empty = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), NULL, 0, FALSE, NULL, NULL);
4412   value = g_variant_get_normal_form (untrusted_empty);
4413   const_str = g_variant_get_bytestring (value);
4414   (void) const_str;
4415   g_variant_unref (value);
4416   g_variant_unref (untrusted_empty);
4417 }
4418 
4419 static void
test_lookup_value(void)4420 test_lookup_value (void)
4421 {
4422   struct {
4423     const gchar *dict, *key, *value;
4424   } cases[] = {
4425     { "@a{ss} {'x':  'y'}",   "x",  "'y'" },
4426     { "@a{ss} {'x':  'y'}",   "y",  NULL  },
4427     { "@a{os} {'/x': 'y'}",   "/x", "'y'" },
4428     { "@a{os} {'/x': 'y'}",   "/y", NULL  },
4429     { "@a{sv} {'x':  <'y'>}", "x",  "'y'" },
4430     { "@a{sv} {'x':  <5>}",   "x",  "5"   },
4431     { "@a{sv} {'x':  <'y'>}", "y",  NULL  }
4432   };
4433   gsize i;
4434 
4435   for (i = 0; i < G_N_ELEMENTS (cases); i++)
4436     {
4437       GVariant *dictionary;
4438       GVariant *value;
4439       gchar *p;
4440 
4441       dictionary = g_variant_parse (NULL, cases[i].dict, NULL, NULL, NULL);
4442       value = g_variant_lookup_value (dictionary, cases[i].key, NULL);
4443       g_variant_unref (dictionary);
4444 
4445       if (value == NULL && cases[i].value == NULL)
4446         continue;
4447 
4448       g_assert_true (value && cases[i].value);
4449       p = g_variant_print (value, FALSE);
4450       g_assert_cmpstr (cases[i].value, ==, p);
4451       g_variant_unref (value);
4452       g_free (p);
4453     }
4454 }
4455 
4456 static void
test_lookup(void)4457 test_lookup (void)
4458 {
4459   const gchar *str;
4460   GVariant *dict;
4461   gboolean ok;
4462   gint num;
4463 
4464   dict = g_variant_parse (NULL,
4465                           "{'a': <5>, 'b': <'c'>}",
4466                           NULL, NULL, NULL);
4467 
4468   ok = g_variant_lookup (dict, "a", "i", &num);
4469   g_assert_true (ok);
4470   g_assert_cmpint (num, ==, 5);
4471 
4472   ok = g_variant_lookup (dict, "a", "&s", &str);
4473   g_assert_false (ok);
4474 
4475   ok = g_variant_lookup (dict, "q", "&s", &str);
4476   g_assert_false (ok);
4477 
4478   ok = g_variant_lookup (dict, "b", "i", &num);
4479   g_assert_false (ok);
4480 
4481   ok = g_variant_lookup (dict, "b", "&s", &str);
4482   g_assert_true (ok);
4483   g_assert_cmpstr (str, ==, "c");
4484 
4485   ok = g_variant_lookup (dict, "q", "&s", &str);
4486   g_assert_false (ok);
4487 
4488   g_variant_unref (dict);
4489 }
4490 
4491 static GVariant *
untrusted(GVariant * a)4492 untrusted (GVariant *a)
4493 {
4494   GVariant *b;
4495   const GVariantType *type;
4496   GBytes *bytes;
4497 
4498   type = g_variant_get_type (a);
4499   bytes = g_variant_get_data_as_bytes (a);
4500   b = g_variant_new_from_bytes (type, bytes, FALSE);
4501   g_bytes_unref (bytes);
4502   g_variant_unref (a);
4503 
4504   return b;
4505 }
4506 
4507 static void
test_compare(void)4508 test_compare (void)
4509 {
4510   GVariant *a;
4511   GVariant *b;
4512 
4513   a = untrusted (g_variant_new_byte (5));
4514   b = g_variant_new_byte (6);
4515   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4516   g_variant_unref (a);
4517   g_variant_unref (b);
4518   a = untrusted (g_variant_new_int16 (G_MININT16));
4519   b = g_variant_new_int16 (G_MAXINT16);
4520   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4521   g_variant_unref (a);
4522   g_variant_unref (b);
4523   a = untrusted (g_variant_new_uint16 (0));
4524   b = g_variant_new_uint16 (G_MAXUINT16);
4525   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4526   g_variant_unref (a);
4527   g_variant_unref (b);
4528   a = untrusted (g_variant_new_int32 (G_MININT32));
4529   b = g_variant_new_int32 (G_MAXINT32);
4530   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4531   g_variant_unref (a);
4532   g_variant_unref (b);
4533   a = untrusted (g_variant_new_uint32 (0));
4534   b = g_variant_new_uint32 (G_MAXUINT32);
4535   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4536   g_variant_unref (a);
4537   g_variant_unref (b);
4538   a = untrusted (g_variant_new_int64 (G_MININT64));
4539   b = g_variant_new_int64 (G_MAXINT64);
4540   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4541   g_variant_unref (a);
4542   g_variant_unref (b);
4543   a = untrusted (g_variant_new_uint64 (0));
4544   b = g_variant_new_uint64 (G_MAXUINT64);
4545   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4546   g_variant_unref (a);
4547   g_variant_unref (b);
4548   a = untrusted (g_variant_new_double (G_MINDOUBLE));
4549   b = g_variant_new_double (G_MAXDOUBLE);
4550   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4551   g_variant_unref (a);
4552   g_variant_unref (b);
4553   a = untrusted (g_variant_new_string ("abc"));
4554   b = g_variant_new_string ("abd");
4555   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4556   g_variant_unref (a);
4557   g_variant_unref (b);
4558   a = untrusted (g_variant_new_object_path ("/abc"));
4559   b = g_variant_new_object_path ("/abd");
4560   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4561   g_variant_unref (a);
4562   g_variant_unref (b);
4563   a = untrusted (g_variant_new_signature ("g"));
4564   b = g_variant_new_signature ("o");
4565   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4566   g_variant_unref (a);
4567   g_variant_unref (b);
4568   a = untrusted (g_variant_new_boolean (FALSE));
4569   b = g_variant_new_boolean (TRUE);
4570   g_assert_cmpint (g_variant_compare (a, b), <, 0);
4571   g_variant_unref (a);
4572   g_variant_unref (b);
4573 }
4574 
4575 static void
test_equal(void)4576 test_equal (void)
4577 {
4578   GVariant *a;
4579   GVariant *b;
4580 
4581   a = untrusted (g_variant_new_byte (5));
4582   b = g_variant_get_normal_form (a);
4583   g_assert_cmpvariant (a, b);
4584   g_variant_unref (a);
4585   g_variant_unref (b);
4586   a = untrusted (g_variant_new_int16 (G_MININT16));
4587   b = g_variant_get_normal_form (a);
4588   g_assert_cmpvariant (a, b);
4589   g_variant_unref (a);
4590   g_variant_unref (b);
4591   a = untrusted (g_variant_new_uint16 (0));
4592   b = g_variant_get_normal_form (a);
4593   g_assert_cmpvariant (a, b);
4594   g_variant_unref (a);
4595   g_variant_unref (b);
4596   a = untrusted (g_variant_new_int32 (G_MININT32));
4597   b = g_variant_get_normal_form (a);
4598   g_assert_cmpvariant (a, b);
4599   g_variant_unref (a);
4600   g_variant_unref (b);
4601   a = untrusted (g_variant_new_uint32 (0));
4602   b = g_variant_get_normal_form (a);
4603   g_assert_cmpvariant (a, b);
4604   g_variant_unref (a);
4605   g_variant_unref (b);
4606   a = untrusted (g_variant_new_int64 (G_MININT64));
4607   b = g_variant_get_normal_form (a);
4608   g_assert_cmpvariant (a, b);
4609   g_variant_unref (a);
4610   g_variant_unref (b);
4611   a = untrusted (g_variant_new_uint64 (0));
4612   b = g_variant_get_normal_form (a);
4613   g_assert_cmpvariant (a, b);
4614   g_variant_unref (a);
4615   g_variant_unref (b);
4616   a = untrusted (g_variant_new_double (G_MINDOUBLE));
4617   b = g_variant_get_normal_form (a);
4618   g_assert_cmpvariant (a, b);
4619   g_variant_unref (a);
4620   g_variant_unref (b);
4621   a = untrusted (g_variant_new_string ("abc"));
4622   g_assert_cmpvariant (a, a);
4623   b = g_variant_get_normal_form (a);
4624   g_assert_cmpvariant (a, b);
4625   g_variant_unref (a);
4626   g_variant_unref (b);
4627   a = untrusted (g_variant_new_object_path ("/abc"));
4628   g_assert_cmpvariant (a, a);
4629   b = g_variant_get_normal_form (a);
4630   a = untrusted (a);
4631   g_assert_cmpvariant (a, b);
4632   g_variant_unref (a);
4633   g_variant_unref (b);
4634   a = untrusted (g_variant_new_signature ("g"));
4635   g_assert_cmpvariant (a, a);
4636   b = g_variant_get_normal_form (a);
4637   a = untrusted (a);
4638   g_assert_cmpvariant (a, b);
4639   g_variant_unref (a);
4640   g_variant_unref (b);
4641   a = untrusted (g_variant_new_boolean (FALSE));
4642   b = g_variant_get_normal_form (a);
4643   g_assert_cmpvariant (a, b);
4644   g_variant_unref (a);
4645   g_variant_unref (b);
4646 }
4647 
4648 static void
test_fixed_array(void)4649 test_fixed_array (void)
4650 {
4651   GVariant *a;
4652   gint32 values[5];
4653   const gint32 *elts;
4654   gsize n_elts;
4655   gsize i;
4656 
4657   n_elts = 0;
4658   a = g_variant_new_parsed ("[1,2,3,4,5]");
4659   elts = g_variant_get_fixed_array (a, &n_elts, sizeof (gint32));
4660   g_assert_cmpuint (n_elts, ==, 5);
4661   for (i = 0; i < 5; i++)
4662     g_assert_cmpint (elts[i], ==, i + 1);
4663   g_variant_unref (a);
4664 
4665   n_elts = 0;
4666   for (i = 0; i < 5; i++)
4667     values[i] = i + 1;
4668   a = g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, values,
4669                                  G_N_ELEMENTS (values), sizeof (values[0]));
4670   g_assert_cmpstr (g_variant_get_type_string (a), ==, "ai");
4671   elts = g_variant_get_fixed_array (a, &n_elts, sizeof (gint32));
4672   g_assert_cmpuint (n_elts, ==, 5);
4673   for (i = 0; i < 5; i++)
4674     g_assert_cmpint (elts[i], ==, i + 1);
4675   g_variant_unref (a);
4676 }
4677 
4678 static void
test_check_format_string(void)4679 test_check_format_string (void)
4680 {
4681   GVariant *value;
4682 
4683   value = g_variant_new ("(sas)", "foo", NULL);
4684   g_variant_ref_sink (value);
4685 
4686   g_assert_true (g_variant_check_format_string (value, "(s*)", TRUE));
4687   g_assert_true (g_variant_check_format_string (value, "(s*)", FALSE));
4688   g_assert_false (g_variant_check_format_string (value, "(u*)", TRUE));
4689   g_assert_false (g_variant_check_format_string (value, "(u*)", FALSE));
4690 
4691   g_assert_true (g_variant_check_format_string (value, "(&s*)", FALSE));
4692   g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
4693   g_assert_false (g_variant_check_format_string (value, "(&s*)", TRUE));
4694   g_test_assert_expected_messages ();
4695 
4696   g_assert_true (g_variant_check_format_string (value, "(s^as)", TRUE));
4697   g_assert_true (g_variant_check_format_string (value, "(s^as)", FALSE));
4698 
4699   g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
4700   g_assert_false (g_variant_check_format_string (value, "(s^a&s)", TRUE));
4701   g_test_assert_expected_messages ();
4702   g_assert_true (g_variant_check_format_string (value, "(s^a&s)", FALSE));
4703 
4704   g_variant_unref (value);
4705 
4706   /* Do it again with a type that will let us put a '&' after a '^' */
4707   value = g_variant_new ("(say)", "foo", NULL);
4708   g_variant_ref_sink (value);
4709 
4710   g_assert_true (g_variant_check_format_string (value, "(s*)", TRUE));
4711   g_assert_true (g_variant_check_format_string (value, "(s*)", FALSE));
4712   g_assert_false (g_variant_check_format_string (value, "(u*)", TRUE));
4713   g_assert_false (g_variant_check_format_string (value, "(u*)", FALSE));
4714 
4715   g_assert_true (g_variant_check_format_string (value, "(&s*)", FALSE));
4716   g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
4717   g_assert_false (g_variant_check_format_string (value, "(&s*)", TRUE));
4718   g_test_assert_expected_messages ();
4719 
4720   g_assert_true (g_variant_check_format_string (value, "(s^ay)", TRUE));
4721   g_assert_true (g_variant_check_format_string (value, "(s^ay)", FALSE));
4722 
4723   g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, "*contains a '&' character*");
4724   g_assert_false (g_variant_check_format_string (value, "(s^&ay)", TRUE));
4725   g_test_assert_expected_messages ();
4726   g_assert_true (g_variant_check_format_string (value, "(s^&ay)", FALSE));
4727 
4728   g_assert_true (g_variant_check_format_string (value, "r", FALSE));
4729   g_assert_true (g_variant_check_format_string (value, "(?a?)", FALSE));
4730 
4731   g_variant_unref (value);
4732 }
4733 
4734 static void
verify_gvariant_checksum(const gchar * sha256,GVariant * v)4735 verify_gvariant_checksum (const gchar  *sha256,
4736 			  GVariant     *v)
4737 
4738 {
4739   gchar *checksum;
4740   checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA256,
4741 					  g_variant_get_data (v),
4742 					  g_variant_get_size (v));
4743   g_assert_cmpstr (sha256, ==, checksum);
4744   g_free (checksum);
4745 }
4746 
4747 static void
verify_gvariant_checksum_va(const gchar * sha256,const gchar * fmt,...)4748 verify_gvariant_checksum_va (const gchar *sha256,
4749 			     const gchar *fmt,
4750 			     ...)
4751 {
4752   va_list args;
4753   GVariant *v;
4754 
4755   va_start (args, fmt);
4756 
4757   v = g_variant_new_va (fmt, NULL, &args);
4758   g_variant_ref_sink (v);
4759 #if G_BYTE_ORDER == G_BIG_ENDIAN
4760   {
4761     GVariant *byteswapped = g_variant_byteswap (v);
4762     g_variant_unref (v);
4763     v = byteswapped;
4764   }
4765 #endif
4766 
4767   va_end (args);
4768 
4769   verify_gvariant_checksum (sha256, v);
4770 
4771   g_variant_unref (v);
4772 }
4773 
4774 static void
test_checksum_basic(void)4775 test_checksum_basic (void)
4776 {
4777   verify_gvariant_checksum_va ("e8a4b2ee7ede79a3afb332b5b6cc3d952a65fd8cffb897f5d18016577c33d7cc",
4778 			       "u", 42);
4779   verify_gvariant_checksum_va ("c53e363c33b00cfce298229ee83856b8a98c2e6126cab13f65899f62473b0df5",
4780 			       "s", "moocow");
4781   verify_gvariant_checksum_va ("2b4c342f5433ebe591a1da77e013d1b72475562d48578dca8b84bac6651c3cb9",
4782 			       "y", 9);
4783   verify_gvariant_checksum_va ("12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca",
4784 			       "t", G_MAXUINT64);
4785   verify_gvariant_checksum_va ("e25a59b24440eb6c833aa79c93b9840e6eab6966add0dacf31df7e9e7000f5b3",
4786 			       "d", 3.14159);
4787   verify_gvariant_checksum_va ("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a",
4788 			       "b", TRUE);
4789   verify_gvariant_checksum_va ("ca2fd00fa001190744c15c317643ab092e7048ce086a243e2be9437c898de1bb",
4790 			       "q", G_MAXUINT16);
4791 }
4792 
4793 static void
test_checksum_nested(void)4794 test_checksum_nested (void)
4795 {
4796   static const char* const strv[] = {"foo", "bar", "baz", NULL};
4797 
4798   verify_gvariant_checksum_va ("31fbc92f08fddaca716188fe4b5d44ae122fc6306fd3c6925af53cfa47ea596d",
4799 			       "(uu)", 41, 43);
4800   verify_gvariant_checksum_va ("01759d683cead856d1d386d59af0578841698a424a265345ad5413122f220de8",
4801 			       "(su)", "moocow", 79);
4802   verify_gvariant_checksum_va ("52b3ae95f19b3e642ea1d01185aea14a09004c1d1712672644427403a8a0afe6",
4803 			       "(qyst)", G_MAXUINT16, 9, "moocow", G_MAXUINT64);
4804   verify_gvariant_checksum_va ("6fc6f4524161c3ae0d316812d7088e3fcd372023edaea2d7821093be40ae1060",
4805 			       "(@ay)", g_variant_new_bytestring ("\xFF\xFF\xFF"));
4806   verify_gvariant_checksum_va ("572aca386e1a983dd23bb6eb6e3dfa72eef9ca7c7744581aa800e18d7d9d0b0b",
4807 			       "(^as)", strv);
4808   verify_gvariant_checksum_va ("4bddf6174c791bb44fc6a4106573031690064df34b741033a0122ed8dc05bcf3",
4809 			       "(yvu)", 254, g_variant_new ("(^as)", strv), 42);
4810 }
4811 
4812 static void
test_gbytes(void)4813 test_gbytes (void)
4814 {
4815   GVariant *a;
4816   GVariant *tuple;
4817   GBytes *bytes;
4818   GBytes *bytes2;
4819   const guint8 values[5] = { 1, 2, 3, 4, 5 };
4820   const guint8 *elts;
4821   gsize n_elts;
4822   gsize i;
4823 
4824   bytes = g_bytes_new (&values, 5);
4825   a = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE);
4826   g_bytes_unref (bytes);
4827   n_elts = 0;
4828   elts = g_variant_get_fixed_array (a, &n_elts, sizeof (guint8));
4829   g_assert_cmpuint (n_elts, ==, 5);
4830   for (i = 0; i < 5; i++)
4831     g_assert_cmpuint (elts[i], ==, i + 1);
4832 
4833   bytes2 = g_variant_get_data_as_bytes (a);
4834   g_variant_unref (a);
4835 
4836   bytes = g_bytes_new (&values, 5);
4837   g_assert_true (g_bytes_equal (bytes, bytes2));
4838   g_bytes_unref (bytes);
4839   g_bytes_unref (bytes2);
4840 
4841   tuple = g_variant_new_parsed ("['foo', 'bar']");
4842   bytes = g_variant_get_data_as_bytes (tuple); /* force serialisation */
4843   a = g_variant_get_child_value (tuple, 1);
4844   bytes2 = g_variant_get_data_as_bytes (a);
4845   g_assert_false (g_bytes_equal (bytes, bytes2));
4846 
4847   g_bytes_unref (bytes);
4848   g_bytes_unref (bytes2);
4849   g_variant_unref (a);
4850   g_variant_unref (tuple);
4851 }
4852 
4853 typedef struct {
4854   const GVariantType *type;
4855   const gchar *in;
4856   const gchar *out;
4857 } ContextTest;
4858 
4859 static void
test_print_context(void)4860 test_print_context (void)
4861 {
4862   ContextTest tests[] = {
4863     { NULL, "(1, 2, 3, 'abc", "          ^^^^" },
4864     { NULL, "[1, 2, 3, 'str']", " ^        ^^^^^" },
4865     { G_VARIANT_TYPE_UINT16, "{ 'abc':'def' }", "  ^^^^^^^^^^^^^^^" },
4866     { NULL, "<5", "    ^" },
4867     { NULL, "'ab\\ux'", "       ^ " },
4868     { NULL, "'ab\\U00efx'", "       ^^^^  " }
4869   };
4870   GVariant *v;
4871   gchar *s;
4872   gsize i;
4873   GError *error = NULL;
4874 
4875   for (i = 0; i < G_N_ELEMENTS (tests); i++)
4876     {
4877       v = g_variant_parse (tests[i].type, tests[i].in, NULL, NULL, &error);
4878       g_assert_null (v);
4879       s = g_variant_parse_error_print_context (error, tests[i].in);
4880       g_assert_nonnull (strstr (s, tests[i].out));
4881       g_free (s);
4882       g_clear_error (&error);
4883     }
4884 }
4885 
4886 static void
test_error_quark(void)4887 test_error_quark (void)
4888 {
4889 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
4890   g_assert_cmpuint (g_variant_parser_get_error_quark (), ==, g_variant_parse_error_quark ());
4891 G_GNUC_END_IGNORE_DEPRECATIONS
4892 }
4893 
4894 static void
test_stack_builder_init(void)4895 test_stack_builder_init (void)
4896 {
4897   GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_BYTESTRING);
4898   GVariant *variant;
4899 
4900   g_variant_builder_add_value (&builder, g_variant_new_byte ('g'));
4901   g_variant_builder_add_value (&builder, g_variant_new_byte ('l'));
4902   g_variant_builder_add_value (&builder, g_variant_new_byte ('i'));
4903   g_variant_builder_add_value (&builder, g_variant_new_byte ('b'));
4904   g_variant_builder_add_value (&builder, g_variant_new_byte ('\0'));
4905 
4906   variant = g_variant_ref_sink (g_variant_builder_end (&builder));
4907   g_assert_nonnull (variant);
4908   g_assert_true (g_variant_type_equal (g_variant_get_type (variant),
4909                                        G_VARIANT_TYPE_BYTESTRING));
4910   g_assert_cmpuint (g_variant_n_children (variant), ==, 5);
4911   g_assert_cmpstr (g_variant_get_bytestring (variant), ==, "glib");
4912   g_variant_unref (variant);
4913 }
4914 
4915 static GVariant *
get_asv(void)4916 get_asv (void)
4917 {
4918   GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
4919 
4920   g_variant_builder_add (&builder, "{s@v}", "foo", g_variant_new_variant (g_variant_new_string ("FOO")));
4921   g_variant_builder_add (&builder, "{s@v}", "bar", g_variant_new_variant (g_variant_new_string ("BAR")));
4922 
4923   return g_variant_ref_sink (g_variant_builder_end (&builder));
4924 }
4925 
4926 static void
test_stack_dict_init(void)4927 test_stack_dict_init (void)
4928 {
4929   GVariant *asv = get_asv ();
4930   GVariantDict dict = G_VARIANT_DICT_INIT (asv);
4931   GVariant *variant;
4932   GVariantIter iter;
4933   gchar *key;
4934   GVariant *value;
4935 
4936   g_variant_dict_insert_value (&dict, "baz", g_variant_new_string ("BAZ"));
4937   g_variant_dict_insert_value (&dict, "quux", g_variant_new_string ("QUUX"));
4938 
4939   variant = g_variant_ref_sink (g_variant_dict_end (&dict));
4940   g_assert_nonnull (variant);
4941   g_assert_true (g_variant_type_equal (g_variant_get_type (variant),
4942                                        G_VARIANT_TYPE_VARDICT));
4943   g_assert_cmpuint (g_variant_n_children (variant), ==, 4);
4944 
4945   g_variant_iter_init (&iter, variant);
4946   while (g_variant_iter_next (&iter, "{sv}", &key, &value))
4947     {
4948       gchar *strup = g_ascii_strup (key, -1);
4949 
4950       g_assert_cmpstr (strup, ==, g_variant_get_string (value, NULL));
4951       g_free (key);
4952       g_free (strup);
4953       g_variant_unref (value);
4954     }
4955 
4956   g_variant_unref (asv);
4957   g_variant_unref (variant);
4958 }
4959 
4960 /* Test checking arbitrary binary data for normal form. This time, it’s a tuple
4961  * with invalid element ends. */
4962 static void
test_normal_checking_tuples(void)4963 test_normal_checking_tuples (void)
4964 {
4965   const guint8 data[] = {
4966     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4967     'a', '(', 'a', 'o', 'a', 'o', 'a', 'a', 'o', 'a', 'a', 'o', ')'
4968   };
4969   gsize size = sizeof (data);
4970   GVariant *variant = NULL;
4971   GVariant *normal_variant = NULL;
4972 
4973   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
4974                                      FALSE, NULL, NULL);
4975   g_assert_nonnull (variant);
4976 
4977   normal_variant = g_variant_get_normal_form (variant);
4978   g_assert_nonnull (normal_variant);
4979 
4980   g_variant_unref (normal_variant);
4981   g_variant_unref (variant);
4982 }
4983 
4984 /* Check that deeply nested variants are not considered in normal form when
4985  * deserialised from untrusted data.*/
4986 static void
test_recursion_limits_variant_in_variant(void)4987 test_recursion_limits_variant_in_variant (void)
4988 {
4989   GVariant *wrapper_variant = NULL;
4990   gsize i;
4991   GBytes *bytes = NULL;
4992   GVariant *deserialised_variant = NULL;
4993 
4994   /* Construct a hierarchy of variants, containing a single string. This is just
4995    * below the maximum recursion level, as a series of nested variant types. */
4996   wrapper_variant = g_variant_new_string ("hello");
4997 
4998   for (i = 0; i < G_VARIANT_MAX_RECURSION_DEPTH - 1; i++)
4999     wrapper_variant = g_variant_new_variant (g_steal_pointer (&wrapper_variant));
5000 
5001   /* Serialise and deserialise it as untrusted data, to force normalisation. */
5002   bytes = g_variant_get_data_as_bytes (wrapper_variant);
5003   deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT,
5004                                                    bytes, FALSE);
5005   g_assert_nonnull (deserialised_variant);
5006   g_assert_true (g_variant_is_normal_form (deserialised_variant));
5007 
5008   g_bytes_unref (bytes);
5009   g_variant_unref (deserialised_variant);
5010 
5011   /* Wrap it once more. Normalisation should now fail. */
5012   wrapper_variant = g_variant_new_variant (g_steal_pointer (&wrapper_variant));
5013 
5014   bytes = g_variant_get_data_as_bytes (wrapper_variant);
5015   deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT,
5016                                                    bytes, FALSE);
5017   g_assert_nonnull (deserialised_variant);
5018   g_assert_false (g_variant_is_normal_form (deserialised_variant));
5019 
5020   g_variant_unref (deserialised_variant);
5021 
5022   /* Deserialise it again, but trusted this time. This should succeed. */
5023   deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT,
5024                                                    bytes, TRUE);
5025   g_assert_nonnull (deserialised_variant);
5026   g_assert_true (g_variant_is_normal_form (deserialised_variant));
5027 
5028   g_bytes_unref (bytes);
5029   g_variant_unref (deserialised_variant);
5030   g_variant_unref (wrapper_variant);
5031 }
5032 
5033 /* Check that deeply nested arrays are not considered in normal form when
5034  * deserialised from untrusted data after being wrapped in a variant. This is
5035  * worth testing, because neither the deeply nested array, nor the variant,
5036  * have a static #GVariantType which is too deep — only when nested together do
5037  * they become too deep. */
5038 static void
test_recursion_limits_array_in_variant(void)5039 test_recursion_limits_array_in_variant (void)
5040 {
5041   GVariant *child_variant = NULL;
5042   GVariant *wrapper_variant = NULL;
5043   gsize i;
5044   GBytes *bytes = NULL;
5045   GVariant *deserialised_variant = NULL;
5046 
5047   /* Construct a hierarchy of arrays, containing a single string. This is just
5048    * below the maximum recursion level, all in a single definite type. */
5049   child_variant = g_variant_new_string ("hello");
5050 
5051   for (i = 0; i < G_VARIANT_MAX_RECURSION_DEPTH - 1; i++)
5052     child_variant = g_variant_new_array (NULL, &child_variant, 1);
5053 
5054   /* Serialise and deserialise it as untrusted data, to force normalisation. */
5055   bytes = g_variant_get_data_as_bytes (child_variant);
5056   deserialised_variant = g_variant_new_from_bytes (g_variant_get_type (child_variant),
5057                                                    bytes, FALSE);
5058   g_assert_nonnull (deserialised_variant);
5059   g_assert_true (g_variant_is_normal_form (deserialised_variant));
5060 
5061   g_bytes_unref (bytes);
5062   g_variant_unref (deserialised_variant);
5063 
5064   /* Wrap it in a variant. Normalisation should now fail. */
5065   wrapper_variant = g_variant_new_variant (g_steal_pointer (&child_variant));
5066 
5067   bytes = g_variant_get_data_as_bytes (wrapper_variant);
5068   deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT,
5069                                                    bytes, FALSE);
5070   g_assert_nonnull (deserialised_variant);
5071   g_assert_false (g_variant_is_normal_form (deserialised_variant));
5072 
5073   g_variant_unref (deserialised_variant);
5074 
5075   /* Deserialise it again, but trusted this time. This should succeed. */
5076   deserialised_variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT,
5077                                                    bytes, TRUE);
5078   g_assert_nonnull (deserialised_variant);
5079   g_assert_true (g_variant_is_normal_form (deserialised_variant));
5080 
5081   g_bytes_unref (bytes);
5082   g_variant_unref (deserialised_variant);
5083   g_variant_unref (wrapper_variant);
5084 }
5085 
5086 /* Test that a nested array with invalid values in its offset table (which point
5087  * from the inner to the outer array) is normalised successfully without
5088  * looping infinitely. */
5089 static void
test_normal_checking_array_offsets_overlapped(void)5090 test_normal_checking_array_offsets_overlapped (void)
5091 {
5092   const guint8 data[] = {
5093     0x01, 0x00,
5094   };
5095   gsize size = sizeof (data);
5096   GVariant *variant = NULL;
5097   GVariant *normal_variant = NULL;
5098   GVariant *expected_variant = NULL;
5099 
5100   variant = g_variant_new_from_data (G_VARIANT_TYPE ("aay"), data, size,
5101                                      FALSE, NULL, NULL);
5102   g_assert_nonnull (variant);
5103 
5104   normal_variant = g_variant_get_normal_form (variant);
5105   g_assert_nonnull (normal_variant);
5106 
5107   expected_variant = g_variant_new_parsed ("[@ay [], []]");
5108   g_assert_cmpvariant (normal_variant, expected_variant);
5109 
5110   g_assert_cmpmem (g_variant_get_data (normal_variant), g_variant_get_size (normal_variant),
5111                    g_variant_get_data (expected_variant), g_variant_get_size (expected_variant));
5112 
5113   g_variant_unref (expected_variant);
5114   g_variant_unref (normal_variant);
5115   g_variant_unref (variant);
5116 }
5117 
5118 /* Test that an array with invalidly large values in its offset table is
5119  * normalised successfully without looping infinitely. */
5120 static void
test_normal_checking_array_offsets(void)5121 test_normal_checking_array_offsets (void)
5122 {
5123   const guint8 data[] = {
5124     0x07, 0xe5, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
5125     'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'g',
5126   };
5127   gsize size = sizeof (data);
5128   GVariant *variant = NULL;
5129   GVariant *normal_variant = NULL;
5130 
5131   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
5132                                      FALSE, NULL, NULL);
5133   g_assert_nonnull (variant);
5134 
5135   normal_variant = g_variant_get_normal_form (variant);
5136   g_assert_nonnull (normal_variant);
5137 
5138   g_variant_unref (normal_variant);
5139   g_variant_unref (variant);
5140 }
5141 
5142 /* This is a regression test that we can't have non-normal values that take up
5143  * significantly more space than the normal equivalent, by specifying the
5144  * offset table entries so that array elements overlap.
5145  *
5146  * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_832242 */
5147 static void
test_normal_checking_array_offsets2(void)5148 test_normal_checking_array_offsets2 (void)
5149 {
5150   const guint8 data[] = {
5151     'h', 'i', '\0',
5152     0x03, 0x00, 0x03,
5153     0x06, 0x00, 0x06,
5154     0x09, 0x00, 0x09,
5155     0x0c, 0x00, 0x0c,
5156     0x0f, 0x00, 0x0f,
5157     0x12, 0x00, 0x12,
5158     0x15, 0x00, 0x15,
5159   };
5160   gsize size = sizeof (data);
5161   const GVariantType *aaaaaaas = G_VARIANT_TYPE ("aaaaaaas");
5162   GVariant *variant = NULL;
5163   GVariant *normal_variant = NULL;
5164   GVariant *expected = NULL;
5165 
5166   variant = g_variant_new_from_data (aaaaaaas, data, size, FALSE, NULL, NULL);
5167   g_assert_nonnull (variant);
5168 
5169   normal_variant = g_variant_get_normal_form (variant);
5170   g_assert_nonnull (normal_variant);
5171   g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 2);
5172 
5173   expected = g_variant_new_parsed (
5174       "[[[[[[['hi', '', ''], [], []], [], []], [], []], [], []], [], []], [], []]");
5175   g_assert_cmpvariant (expected, variant);
5176   g_assert_cmpvariant (expected, normal_variant);
5177 
5178   g_variant_unref (expected);
5179   g_variant_unref (normal_variant);
5180   g_variant_unref (variant);
5181 }
5182 
5183 /* Test that an otherwise-valid serialised GVariant is considered non-normal if
5184  * its offset table entries are too wide.
5185  *
5186  * See §2.3.6 (Framing Offsets) of the GVariant specification. */
5187 static void
test_normal_checking_array_offsets_minimal_sized(void)5188 test_normal_checking_array_offsets_minimal_sized (void)
5189 {
5190   GVariantBuilder builder;
5191   gsize i;
5192   GVariant *aay_constructed = NULL;
5193   const guint8 *data = NULL;
5194   guint8 *data_owned = NULL;
5195   GVariant *aay_deserialised = NULL;
5196   GVariant *aay_normalised = NULL;
5197 
5198   /* Construct an array of type aay, consisting of 128 elements which are each
5199    * an empty array, i.e. `[[] * 128]`. This is chosen because the inner
5200    * elements are variable sized (making the outer array variable sized, so it
5201    * must have an offset table), but they are also zero-sized when serialised.
5202    * So the serialised representation of @aay_constructed consists entirely of
5203    * its offset table, which is entirely zeroes.
5204    *
5205    * The array is chosen to be 128 elements long because that means offset
5206    * table entries which are 1 byte long. If the elements in the array were
5207    * non-zero-sized (to the extent that the overall array is ≥256 bytes long),
5208    * the offset table entries would end up being 2 bytes long. */
5209   g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay"));
5210 
5211   for (i = 0; i < 128; i++)
5212     g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
5213 
5214   aay_constructed = g_variant_builder_end (&builder);
5215 
5216   /* Verify that the constructed array is in normal form, and its serialised
5217    * form is `b'\0' * 128`. */
5218   g_assert_true (g_variant_is_normal_form (aay_constructed));
5219   g_assert_cmpuint (g_variant_n_children (aay_constructed), ==, 128);
5220   g_assert_cmpuint (g_variant_get_size (aay_constructed), ==, 128);
5221 
5222   data = g_variant_get_data (aay_constructed);
5223   for (i = 0; i < g_variant_get_size (aay_constructed); i++)
5224     g_assert_cmpuint (data[i], ==, 0);
5225 
5226   /* Construct a serialised `aay` GVariant which is `b'\0' * 256`. This has to
5227    * be a non-normal form of `[[] * 128]`, with 2-byte-long offset table
5228    * entries, because each offset table entry has to be able to reference all of
5229    * the byte boundaries in the container. All the entries in the offset table
5230    * are zero, so all the elements of the array are zero-sized. */
5231   data = data_owned = g_malloc0 (256);
5232   aay_deserialised = g_variant_new_from_data (G_VARIANT_TYPE ("aay"),
5233                                               data,
5234                                               256,
5235                                               FALSE,
5236                                               g_free,
5237                                               g_steal_pointer (&data_owned));
5238 
5239   g_assert_false (g_variant_is_normal_form (aay_deserialised));
5240   g_assert_cmpuint (g_variant_n_children (aay_deserialised), ==, 128);
5241   g_assert_cmpuint (g_variant_get_size (aay_deserialised), ==, 256);
5242 
5243   data = g_variant_get_data (aay_deserialised);
5244   for (i = 0; i < g_variant_get_size (aay_deserialised); i++)
5245     g_assert_cmpuint (data[i], ==, 0);
5246 
5247   /* Get its normal form. That should change the serialised size. */
5248   aay_normalised = g_variant_get_normal_form (aay_deserialised);
5249 
5250   g_assert_true (g_variant_is_normal_form (aay_normalised));
5251   g_assert_cmpuint (g_variant_n_children (aay_normalised), ==, 128);
5252   g_assert_cmpuint (g_variant_get_size (aay_normalised), ==, 128);
5253 
5254   data = g_variant_get_data (aay_normalised);
5255   for (i = 0; i < g_variant_get_size (aay_normalised); i++)
5256     g_assert_cmpuint (data[i], ==, 0);
5257 
5258   g_variant_unref (aay_normalised);
5259   g_variant_unref (aay_deserialised);
5260   g_variant_unref (aay_constructed);
5261 }
5262 
5263 /* Test that a tuple with invalidly large values in its offset table is
5264  * normalised successfully without looping infinitely. */
5265 static void
test_normal_checking_tuple_offsets(void)5266 test_normal_checking_tuple_offsets (void)
5267 {
5268   const guint8 data[] = {
5269     0x07, 0xe5, 0x00, 0x07, 0x00, 0x07,
5270     '(', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', ')',
5271   };
5272   gsize size = sizeof (data);
5273   GVariant *variant = NULL;
5274   GVariant *normal_variant = NULL;
5275 
5276   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
5277                                      FALSE, NULL, NULL);
5278   g_assert_nonnull (variant);
5279 
5280   normal_variant = g_variant_get_normal_form (variant);
5281   g_assert_nonnull (normal_variant);
5282 
5283   g_variant_unref (normal_variant);
5284   g_variant_unref (variant);
5285 }
5286 
5287 /* This is a regression test that we can't have non-normal values that take up
5288  * significantly more space than the normal equivalent, by specifying the
5289  * offset table entries so that tuple elements overlap.
5290  *
5291  * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838503 and
5292  * https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_838513 */
5293 static void
test_normal_checking_tuple_offsets2(void)5294 test_normal_checking_tuple_offsets2 (void)
5295 {
5296   const GVariantType *data_type = G_VARIANT_TYPE ("(yyaiyyaiyy)");
5297   const guint8 data[] = {
5298     0x12, 0x34, 0x56, 0x78, 0x01,
5299     /*
5300          ^───────────────────┘
5301 
5302     ^^^^^^^^^^                   1st yy
5303           ^^^^^^^^^^             2nd yy
5304                 ^^^^^^^^^^       3rd yy
5305                             ^^^^ Framing offsets
5306      */
5307 
5308   /* If this variant was encoded normally, it would be something like this:
5309    * 0x12, 0x34,  pad,  pad, [array bytes], 0x56, 0x78,  pad,  pad, [array bytes], 0x9A, 0xBC, 0xXX
5310    *                                      ^─────────────────────────────────────────────────────┘
5311    *
5312    * ^^^^^^^^^^                                                                                     1st yy
5313    *                                        ^^^^^^^^^^                                              2nd yy
5314    *                                                                               ^^^^^^^^^^       3rd yy
5315    *                                                                                           ^^^^ Framing offsets
5316    */
5317   };
5318   gsize size = sizeof (data);
5319   GVariant *variant = NULL;
5320   GVariant *normal_variant = NULL;
5321   GVariant *expected = NULL;
5322 
5323   variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
5324   g_assert_nonnull (variant);
5325 
5326   normal_variant = g_variant_get_normal_form (variant);
5327   g_assert_nonnull (normal_variant);
5328   g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3);
5329 
5330   expected = g_variant_new_parsed (
5331       "@(yyaiyyaiyy) (0x12, 0x34, [], 0x00, 0x00, [], 0x00, 0x00)");
5332   g_assert_cmpvariant (expected, variant);
5333   g_assert_cmpvariant (expected, normal_variant);
5334 
5335   g_variant_unref (expected);
5336   g_variant_unref (normal_variant);
5337   g_variant_unref (variant);
5338 }
5339 
5340 /* This is a regression test that overlapping entries in the offset table are
5341  * decoded consistently, even though they’re non-normal.
5342  *
5343  * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */
5344 static void
test_normal_checking_tuple_offsets3(void)5345 test_normal_checking_tuple_offsets3 (void)
5346 {
5347   /* The expected decoding of this non-normal byte stream is complex. See
5348    * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant
5349    * specification.
5350    *
5351    * The rule “Child Values Overlapping Framing Offsets” from the specification
5352    * says that the first `ay` must be decoded as `[0x01]` even though it
5353    * overlaps the first byte of the offset table. However, since commit
5354    * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow
5355    * this as it’s exploitable. So the first `ay` must be given a default value.
5356    *
5357    * The second and third `ay`s must be given default values because of rule
5358    * “End Boundary Precedes Start Boundary”.
5359    *
5360    * The `i` must be given a default value because of rule “Start or End
5361    * Boundary of a Child Falls Outside the Container”.
5362    */
5363   const GVariantType *data_type = G_VARIANT_TYPE ("(ayayiay)");
5364   const guint8 data[] = {
5365     0x01, 0x00, 0x02,
5366     /*
5367                ^──┘
5368 
5369     ^^^^^^^^^^                   1st ay, bytes 0-2 (but given a default value anyway, see above)
5370                                  2nd ay, bytes 2-0
5371                                      i,  bytes 0-4
5372                                  3rd ay, bytes 4-1
5373           ^^^^^^^^^^ Framing offsets
5374      */
5375   };
5376   gsize size = sizeof (data);
5377   GVariant *variant = NULL;
5378   GVariant *normal_variant = NULL;
5379   GVariant *expected = NULL;
5380 
5381   variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
5382   g_assert_nonnull (variant);
5383 
5384   g_assert_false (g_variant_is_normal_form (variant));
5385 
5386   normal_variant = g_variant_get_normal_form (variant);
5387   g_assert_nonnull (normal_variant);
5388   g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3);
5389 
5390   expected = g_variant_new_parsed ("@(ayayiay) ([], [], 0, [])");
5391   g_assert_cmpvariant (expected, variant);
5392   g_assert_cmpvariant (expected, normal_variant);
5393 
5394   g_variant_unref (expected);
5395   g_variant_unref (normal_variant);
5396   g_variant_unref (variant);
5397 }
5398 
5399 /* This is a regression test that overlapping entries in the offset table are
5400  * decoded consistently, even though they’re non-normal.
5401  *
5402  * See https://gitlab.gnome.org/GNOME/glib/-/issues/2121#note_910935 */
5403 static void
test_normal_checking_tuple_offsets4(void)5404 test_normal_checking_tuple_offsets4 (void)
5405 {
5406   /* The expected decoding of this non-normal byte stream is complex. See
5407    * section 2.7.3 (Handling Non-Normal Serialised Data) of the GVariant
5408    * specification.
5409    *
5410    * The rule “Child Values Overlapping Framing Offsets” from the specification
5411    * says that the first `ay` must be decoded as `[0x01]` even though it
5412    * overlaps the first byte of the offset table. However, since commit
5413    * 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3, GLib explicitly doesn’t allow
5414    * this as it’s exploitable. So the first `ay` must be given a default value.
5415    *
5416    * The second `ay` must be given a default value because of rule “End Boundary
5417    * Precedes Start Boundary”.
5418    *
5419    * The third `ay` must be given a default value because its framing offsets
5420    * overlap that of the first `ay`.
5421    */
5422   const GVariantType *data_type = G_VARIANT_TYPE ("(ayayay)");
5423   const guint8 data[] = {
5424     0x01, 0x00, 0x02,
5425     /*
5426                ^──┘
5427 
5428     ^^^^^^^^^^                   1st ay, bytes 0-2 (but given a default value anyway, see above)
5429                                  2nd ay, bytes 2-0
5430                                  3rd ay, bytes 0-1
5431           ^^^^^^^^^^ Framing offsets
5432      */
5433   };
5434   gsize size = sizeof (data);
5435   GVariant *variant = NULL;
5436   GVariant *normal_variant = NULL;
5437   GVariant *expected = NULL;
5438 
5439   variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
5440   g_assert_nonnull (variant);
5441 
5442   g_assert_false (g_variant_is_normal_form (variant));
5443 
5444   normal_variant = g_variant_get_normal_form (variant);
5445   g_assert_nonnull (normal_variant);
5446   g_assert_cmpuint (g_variant_get_size (normal_variant), <=, size * 3);
5447 
5448   expected = g_variant_new_parsed ("@(ayayay) ([], [], [])");
5449   g_assert_cmpvariant (expected, variant);
5450   g_assert_cmpvariant (expected, normal_variant);
5451 
5452   g_variant_unref (expected);
5453   g_variant_unref (normal_variant);
5454   g_variant_unref (variant);
5455 }
5456 
5457 /* This is a regression test that dereferencing the first element in the offset
5458  * table doesn’t dereference memory before the start of the GVariant. The first
5459  * element in the offset table gives the offset of the final member in the
5460  * tuple (the offset table is stored in reverse), and the position of this final
5461  * member is needed to check that none of the tuple members overlap with the
5462  * offset table
5463  *
5464  * See https://gitlab.gnome.org/GNOME/glib/-/issues/2840 */
5465 static void
test_normal_checking_tuple_offsets5(void)5466 test_normal_checking_tuple_offsets5 (void)
5467 {
5468   /* A tuple of type (sss) in normal form would have an offset table with two
5469    * entries:
5470    *  - The first entry (lowest index in the table) gives the offset of the
5471    *    third `s` in the tuple, as the offset table is reversed compared to the
5472    *    tuple members.
5473    *  - The second entry (highest index in the table) gives the offset of the
5474    *    second `s` in the tuple.
5475    *  - The offset of the first `s` in the tuple is always 0.
5476    *
5477    * See §2.5.4 (Structures) of the GVariant specification for details, noting
5478    * that the table is only layed out this way because all three members of the
5479    * tuple have non-fixed sizes.
5480    *
5481    * It’s not clear whether the 0xaa data of this variant is part of the strings
5482    * in the tuple, or part of the offset table. It doesn’t really matter. This
5483    * is a regression test to check that the code to validate the offset table
5484    * doesn’t unconditionally try to access the first entry in the offset table
5485    * by subtracting the table size from the end of the GVariant data.
5486    *
5487    * In this non-normal case, that would result in an address off the start of
5488    * the GVariant data, and an out-of-bounds read, because the GVariant is one
5489    * byte long, but the offset table is calculated as two bytes long (with 1B
5490    * sized entries) from the tuple’s type.
5491    */
5492   const GVariantType *data_type = G_VARIANT_TYPE ("(sss)");
5493   const guint8 data[] = { 0xaa };
5494   gsize size = sizeof (data);
5495   GVariant *variant = NULL;
5496   GVariant *normal_variant = NULL;
5497   GVariant *expected = NULL;
5498 
5499   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2840");
5500 
5501   variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
5502   g_assert_nonnull (variant);
5503 
5504   g_assert_false (g_variant_is_normal_form (variant));
5505 
5506   normal_variant = g_variant_get_normal_form (variant);
5507   g_assert_nonnull (normal_variant);
5508 
5509   expected = g_variant_new_parsed ("('', '', '')");
5510   g_assert_cmpvariant (expected, variant);
5511   g_assert_cmpvariant (expected, normal_variant);
5512 
5513   g_variant_unref (expected);
5514   g_variant_unref (normal_variant);
5515   g_variant_unref (variant);
5516 }
5517 
5518 /* Test that an otherwise-valid serialised GVariant is considered non-normal if
5519  * its offset table entries are too wide.
5520  *
5521  * See §2.3.6 (Framing Offsets) of the GVariant specification. */
5522 static void
test_normal_checking_tuple_offsets_minimal_sized(void)5523 test_normal_checking_tuple_offsets_minimal_sized (void)
5524 {
5525   GString *type_string = NULL;
5526   GVariantBuilder builder;
5527   gsize i;
5528   GVariant *ray_constructed = NULL;
5529   const guint8 *data = NULL;
5530   guint8 *data_owned = NULL;
5531   GVariant *ray_deserialised = NULL;
5532   GVariant *ray_normalised = NULL;
5533 
5534   /* Construct a tuple of type (ay…ay), consisting of 129 members which are each
5535    * an empty array, i.e. `([] * 129)`. This is chosen because the inner
5536    * members are variable sized, so the outer tuple must have an offset table,
5537    * but they are also zero-sized when serialised. So the serialised
5538    * representation of @ray_constructed consists entirely of its offset table,
5539    * which is entirely zeroes.
5540    *
5541    * The tuple is chosen to be 129 members long because that means it has 128
5542    * offset table entries which are 1 byte long each. If the members in the
5543    * tuple were non-zero-sized (to the extent that the overall tuple is ≥256
5544    * bytes long), the offset table entries would end up being 2 bytes long.
5545    *
5546    * 129 members are used unlike 128 array elements in
5547    * test_normal_checking_array_offsets_minimal_sized(), because the last member
5548    * in a tuple never needs an offset table entry. */
5549   type_string = g_string_new ("");
5550   g_string_append_c (type_string, '(');
5551   for (i = 0; i < 129; i++)
5552     g_string_append (type_string, "ay");
5553   g_string_append_c (type_string, ')');
5554 
5555   g_variant_builder_init (&builder, G_VARIANT_TYPE (type_string->str));
5556 
5557   for (i = 0; i < 129; i++)
5558     g_variant_builder_add_value (&builder, g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0));
5559 
5560   ray_constructed = g_variant_builder_end (&builder);
5561 
5562   /* Verify that the constructed tuple is in normal form, and its serialised
5563    * form is `b'\0' * 128`. */
5564   g_assert_true (g_variant_is_normal_form (ray_constructed));
5565   g_assert_cmpuint (g_variant_n_children (ray_constructed), ==, 129);
5566   g_assert_cmpuint (g_variant_get_size (ray_constructed), ==, 128);
5567 
5568   data = g_variant_get_data (ray_constructed);
5569   for (i = 0; i < g_variant_get_size (ray_constructed); i++)
5570     g_assert_cmpuint (data[i], ==, 0);
5571 
5572   /* Construct a serialised `(ay…ay)` GVariant which is `b'\0' * 256`. This has
5573    * to be a non-normal form of `([] * 129)`, with 2-byte-long offset table
5574    * entries, because each offset table entry has to be able to reference all of
5575    * the byte boundaries in the container. All the entries in the offset table
5576    * are zero, so all the members of the tuple are zero-sized. */
5577   data = data_owned = g_malloc0 (256);
5578   ray_deserialised = g_variant_new_from_data (G_VARIANT_TYPE (type_string->str),
5579                                               data,
5580                                               256,
5581                                               FALSE,
5582                                               g_free,
5583                                               g_steal_pointer (&data_owned));
5584 
5585   g_assert_false (g_variant_is_normal_form (ray_deserialised));
5586   g_assert_cmpuint (g_variant_n_children (ray_deserialised), ==, 129);
5587   g_assert_cmpuint (g_variant_get_size (ray_deserialised), ==, 256);
5588 
5589   data = g_variant_get_data (ray_deserialised);
5590   for (i = 0; i < g_variant_get_size (ray_deserialised); i++)
5591     g_assert_cmpuint (data[i], ==, 0);
5592 
5593   /* Get its normal form. That should change the serialised size. */
5594   ray_normalised = g_variant_get_normal_form (ray_deserialised);
5595 
5596   g_assert_true (g_variant_is_normal_form (ray_normalised));
5597   g_assert_cmpuint (g_variant_n_children (ray_normalised), ==, 129);
5598   g_assert_cmpuint (g_variant_get_size (ray_normalised), ==, 128);
5599 
5600   data = g_variant_get_data (ray_normalised);
5601   for (i = 0; i < g_variant_get_size (ray_normalised); i++)
5602     g_assert_cmpuint (data[i], ==, 0);
5603 
5604   g_variant_unref (ray_normalised);
5605   g_variant_unref (ray_deserialised);
5606   g_variant_unref (ray_constructed);
5607   g_string_free (type_string, TRUE);
5608 }
5609 
5610 /* Test that an empty object path is normalised successfully to the base object
5611  * path, ‘/’. */
5612 static void
test_normal_checking_empty_object_path(void)5613 test_normal_checking_empty_object_path (void)
5614 {
5615   const guint8 data[] = {
5616     0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
5617     '(', 'h', '(', 'a', 'i', 'a', 'b', 'i', 'o', ')', ')',
5618   };
5619   gsize size = sizeof (data);
5620   GVariant *variant = NULL;
5621   GVariant *normal_variant = NULL;
5622 
5623   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
5624                                      FALSE, NULL, NULL);
5625   g_assert_nonnull (variant);
5626 
5627   normal_variant = g_variant_get_normal_form (variant);
5628   g_assert_nonnull (normal_variant);
5629 
5630   g_variant_unref (normal_variant);
5631   g_variant_unref (variant);
5632 }
5633 
5634 /* Test that constructing a #GVariant from data which is not correctly aligned
5635  * for the variant type is OK, by loading a variant from data at various offsets
5636  * which are aligned and unaligned. When unaligned, a slow construction path
5637  * should be taken. */
5638 static void
test_unaligned_construction(void)5639 test_unaligned_construction (void)
5640 {
5641   const guint8 data[] = {
5642     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
5643     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
5644   };
5645   GVariant *variant = NULL;
5646   GVariant *normal_variant = NULL;
5647   gsize i, offset;
5648   const struct {
5649     const GVariantType *type;
5650     gsize size;
5651     gsize max_offset;
5652   } vectors[] = {
5653     { G_VARIANT_TYPE_UINT64, sizeof (guint64), sizeof (guint64) },
5654     { G_VARIANT_TYPE_UINT32, sizeof (guint32), sizeof (guint32) },
5655     { G_VARIANT_TYPE_UINT16, sizeof (guint16), sizeof (guint16) },
5656     { G_VARIANT_TYPE_BYTE, sizeof (guint8), 3 },
5657   };
5658 
5659   G_STATIC_ASSERT (sizeof (guint64) * 2 <= sizeof (data));
5660 
5661   for (i = 0; i < G_N_ELEMENTS (vectors); i++)
5662     {
5663       for (offset = 0; offset < vectors[i].max_offset; offset++)
5664         {
5665           variant = g_variant_new_from_data (vectors[i].type, data + offset,
5666                                              vectors[i].size,
5667                                              FALSE, NULL, NULL);
5668           g_assert_nonnull (variant);
5669 
5670           normal_variant = g_variant_get_normal_form (variant);
5671           g_assert_nonnull (normal_variant);
5672 
5673           g_variant_unref (normal_variant);
5674           g_variant_unref (variant);
5675         }
5676     }
5677 }
5678 
5679 int
main(int argc,char ** argv)5680 main (int argc, char **argv)
5681 {
5682   guint i;
5683 
5684   g_test_init (&argc, &argv, NULL);
5685   g_test_bug_base ("");
5686 
5687   g_test_add_func ("/gvariant/type", test_gvarianttype);
5688   g_test_add_func ("/gvariant/type/string-scan/recursion/tuple",
5689                    test_gvarianttype_string_scan_recursion_tuple);
5690   g_test_add_func ("/gvariant/type/string-scan/recursion/array",
5691                    test_gvarianttype_string_scan_recursion_array);
5692   g_test_add_func ("/gvariant/typeinfo", test_gvarianttypeinfo);
5693   g_test_add_func ("/gvariant/serialiser/maybe", test_maybes);
5694   g_test_add_func ("/gvariant/serialiser/array", test_arrays);
5695   g_test_add_func ("/gvariant/serialiser/tuple", test_tuples);
5696   g_test_add_func ("/gvariant/serialiser/variant", test_variants);
5697   g_test_add_func ("/gvariant/serialiser/strings", test_strings);
5698   g_test_add_func ("/gvariant/serialiser/byteswap", test_byteswaps);
5699   g_test_add_func ("/gvariant/serialiser/children", test_serialiser_children);
5700 
5701   for (i = 1; i <= 20; i += 4)
5702     {
5703       char *testname;
5704 
5705       testname = g_strdup_printf ("/gvariant/serialiser/fuzz/%u%%", i);
5706       g_test_add_data_func (testname, GINT_TO_POINTER (i),
5707                             (gpointer) test_fuzzes);
5708       g_free (testname);
5709     }
5710 
5711   g_test_add_func ("/gvariant/string", test_string);
5712   g_test_add_func ("/gvariant/utf8", test_utf8);
5713   g_test_add_func ("/gvariant/containers", test_containers);
5714   g_test_add_func ("/gvariant/format-strings", test_format_strings);
5715   g_test_add_func ("/gvariant/invalid-varargs", test_invalid_varargs);
5716   g_test_add_func ("/gvariant/varargs", test_varargs);
5717   g_test_add_func ("/gvariant/varargs/subprocess/empty-array", test_varargs_empty_array);
5718   g_test_add_func ("/gvariant/valist", test_valist);
5719   g_test_add_func ("/gvariant/builder-memory", test_builder_memory);
5720   g_test_add_func ("/gvariant/hashing", test_hashing);
5721   g_test_add_func ("/gvariant/byteswap", test_gv_byteswap);
5722   g_test_add_func ("/gvariant/byteswap/non-normal-non-aligned", test_gv_byteswap_non_normal_non_aligned);
5723   g_test_add_func ("/gvariant/parser", test_parses);
5724   g_test_add_func ("/gvariant/parser/integer-bounds", test_parser_integer_bounds);
5725   g_test_add_func ("/gvariant/parser/recursion", test_parser_recursion);
5726   g_test_add_func ("/gvariant/parse-failures", test_parse_failures);
5727   g_test_add_func ("/gvariant/parse-positional", test_parse_positional);
5728   g_test_add_func ("/gvariant/parse/subprocess/bad-format-char", test_parse_bad_format_char);
5729   g_test_add_func ("/gvariant/parse/subprocess/bad-format-string", test_parse_bad_format_string);
5730   g_test_add_func ("/gvariant/parse/subprocess/bad-args", test_parse_bad_args);
5731   g_test_add_func ("/gvariant/floating", test_floating);
5732   g_test_add_func ("/gvariant/bytestring", test_bytestring);
5733   g_test_add_func ("/gvariant/lookup-value", test_lookup_value);
5734   g_test_add_func ("/gvariant/lookup", test_lookup);
5735   g_test_add_func ("/gvariant/compare", test_compare);
5736   g_test_add_func ("/gvariant/equal", test_equal);
5737   g_test_add_func ("/gvariant/fixed-array", test_fixed_array);
5738   g_test_add_func ("/gvariant/check-format-string", test_check_format_string);
5739 
5740   g_test_add_func ("/gvariant/checksum-basic", test_checksum_basic);
5741   g_test_add_func ("/gvariant/checksum-nested", test_checksum_nested);
5742 
5743   g_test_add_func ("/gvariant/gbytes", test_gbytes);
5744   g_test_add_func ("/gvariant/print-context", test_print_context);
5745   g_test_add_func ("/gvariant/error-quark", test_error_quark);
5746 
5747   g_test_add_func ("/gvariant/stack-builder-init", test_stack_builder_init);
5748   g_test_add_func ("/gvariant/stack-dict-init", test_stack_dict_init);
5749 
5750   g_test_add_func ("/gvariant/normal-checking/tuples",
5751                    test_normal_checking_tuples);
5752   g_test_add_func ("/gvariant/normal-checking/array-offsets/overlapped",
5753                    test_normal_checking_array_offsets_overlapped);
5754   g_test_add_func ("/gvariant/normal-checking/array-offsets",
5755                    test_normal_checking_array_offsets);
5756   g_test_add_func ("/gvariant/normal-checking/array-offsets2",
5757                    test_normal_checking_array_offsets2);
5758   g_test_add_func ("/gvariant/normal-checking/array-offsets/minimal-sized",
5759                    test_normal_checking_array_offsets_minimal_sized);
5760   g_test_add_func ("/gvariant/normal-checking/tuple-offsets",
5761                    test_normal_checking_tuple_offsets);
5762   g_test_add_func ("/gvariant/normal-checking/tuple-offsets2",
5763                    test_normal_checking_tuple_offsets2);
5764   g_test_add_func ("/gvariant/normal-checking/tuple-offsets3",
5765                    test_normal_checking_tuple_offsets3);
5766   g_test_add_func ("/gvariant/normal-checking/tuple-offsets4",
5767                    test_normal_checking_tuple_offsets4);
5768   g_test_add_func ("/gvariant/normal-checking/tuple-offsets5",
5769                    test_normal_checking_tuple_offsets5);
5770   g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized",
5771                    test_normal_checking_tuple_offsets_minimal_sized);
5772   g_test_add_func ("/gvariant/normal-checking/empty-object-path",
5773                    test_normal_checking_empty_object_path);
5774 
5775   g_test_add_func ("/gvariant/recursion-limits/variant-in-variant",
5776                    test_recursion_limits_variant_in_variant);
5777   g_test_add_func ("/gvariant/recursion-limits/array-in-variant",
5778                    test_recursion_limits_array_in_variant);
5779 
5780   g_test_add_func ("/gvariant/unaligned-construction",
5781                    test_unaligned_construction);
5782 
5783   return g_test_run ();
5784 }
5785