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