• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2007, 2008 Ryan Lortie
3  * Copyright © 2010 Codethink Limited
4  * Copyright © 2020 William Manley
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  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21 
22 /* Prologue {{{1 */
23 #include "config.h"
24 
25 #include "gvariant-serialiser.h"
26 
27 #include <glib/gvariant-internal.h>
28 #include <glib/gtestutils.h>
29 #include <glib/gstrfuncs.h>
30 #include <glib/gtypes.h>
31 
32 #include <string.h>
33 
34 
35 /* GVariantSerialiser
36  *
37  * After this prologue section, this file has roughly 2 parts.
38  *
39  * The first part is split up into sections according to various
40  * container types.  Maybe, Array, Tuple, Variant.  The Maybe and Array
41  * sections are subdivided for element types being fixed or
42  * variable-sized types.
43  *
44  * Each section documents the format of that particular type of
45  * container and implements 5 functions for dealing with it:
46  *
47  *  n_children:
48  *    - determines (according to serialised data) how many child values
49  *      are inside a particular container value.
50  *
51  *  get_child:
52  *    - gets the type of and the serialised data corresponding to a
53  *      given child value within the container value.
54  *
55  *  needed_size:
56  *    - determines how much space would be required to serialise a
57  *      container of this type, containing the given children so that
58  *      buffers can be preallocated before serialising.
59  *
60  *  serialise:
61  *    - write the serialised data for a container of this type,
62  *      containing the given children, to a buffer.
63  *
64  *  is_normal:
65  *    - check the given data to ensure that it is in normal form.  For a
66  *      given set of child values, there is exactly one normal form for
67  *      the serialised data of a container.  Other forms are possible
68  *      while maintaining the same children (for example, by inserting
69  *      something other than zero bytes as padding) but only one form is
70  *      the normal form.
71  *
72  * The second part contains the main entry point for each of the above 5
73  * functions and logic to dispatch it to the handler for the appropriate
74  * container type code.
75  *
76  * The second part also contains a routine to byteswap serialised
77  * values.  This code makes use of the n_children() and get_child()
78  * functions above to do its work so no extra support is needed on a
79  * per-container-type basis.
80  *
81  * There is also additional code for checking for normal form.  All
82  * numeric types are always in normal form since the full range of
83  * values is permitted (eg: 0 to 255 is a valid byte).  Special checks
84  * need to be performed for booleans (only 0 or 1 allowed), strings
85  * (properly nul-terminated) and object paths and signature strings
86  * (meeting the D-Bus specification requirements).  Depth checks need to be
87  * performed for nested types (arrays, tuples, and variants), to avoid massive
88  * recursion which could exhaust our stack when handling untrusted input.
89  */
90 
91 /* < private >
92  * GVariantSerialised:
93  * @type_info: the #GVariantTypeInfo of this value
94  * @data: (nullable): the serialised data of this value, or %NULL
95  * @size: the size of this value
96  *
97  * A structure representing a GVariant in serialised form.  This
98  * structure is used with #GVariantSerialisedFiller functions and as the
99  * primary interface to the serialiser.  See #GVariantSerialisedFiller
100  * for a description of its use there.
101  *
102  * When used with the serialiser API functions, the following invariants
103  * apply to all #GVariantTypeSerialised structures passed to and
104  * returned from the serialiser.
105  *
106  * @type_info must be non-%NULL.
107  *
108  * @data must be properly aligned for the type described by @type_info.
109  *
110  * If @type_info describes a fixed-sized type then @size must always be
111  * equal to the fixed size of that type.
112  *
113  * For fixed-sized types (and only fixed-sized types), @data may be
114  * %NULL even if @size is non-zero.  This happens when a framing error
115  * occurs while attempting to extract a fixed-sized value out of a
116  * variable-sized container.  There is no data to return for the
117  * fixed-sized type, yet @size must be non-zero.  The effect of this
118  * combination should be as if @data were a pointer to an
119  * appropriately-sized zero-filled region.
120  *
121  * @depth has no restrictions; the depth of a top-level serialised #GVariant is
122  * zero, and it increases for each level of nested child.
123  *
124  * @checked_offsets_up_to is always ≥ @ordered_offsets_up_to
125  */
126 
127 /* < private >
128  * g_variant_serialised_check:
129  * @serialised: a #GVariantSerialised struct
130  *
131  * Checks @serialised for validity according to the invariants described
132  * above.
133  *
134  * Returns: %TRUE if @serialised is valid; %FALSE otherwise
135  */
136 gboolean
g_variant_serialised_check(GVariantSerialised serialised)137 g_variant_serialised_check (GVariantSerialised serialised)
138 {
139   gsize fixed_size;
140   guint alignment;
141 
142   if (serialised.type_info == NULL)
143     return FALSE;
144   g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
145 
146   if (fixed_size != 0 && serialised.size != fixed_size)
147     return FALSE;
148   else if (fixed_size == 0 &&
149            !(serialised.size == 0 || serialised.data != NULL))
150     return FALSE;
151 
152   if (serialised.ordered_offsets_up_to > serialised.checked_offsets_up_to)
153     return FALSE;
154 
155   /* Depending on the native alignment requirements of the machine, the
156    * compiler will insert either 3 or 7 padding bytes after the char.
157    * This will result in the sizeof() the struct being 12 or 16.
158    * Subtract 9 to get 3 or 7 which is a nice bitmask to apply to get
159    * the alignment bits that we "care about" being zero: in the
160    * 4-aligned case, we care about 2 bits, and in the 8-aligned case, we
161    * care about 3 bits.
162    */
163   alignment &= sizeof (struct {
164                          char a;
165                          union {
166                            guint64 x;
167                            void *y;
168                            gdouble z;
169                          } b;
170                        }
171                       ) - 9;
172 
173   /* Some OSes (FreeBSD is a known example) have a malloc() that returns
174    * unaligned memory if you request small sizes.  'malloc (1);', for
175    * example, has been seen to return pointers aligned to 6 mod 16.
176    *
177    * Check if this is a small allocation and return without enforcing
178    * the alignment assertion if this is the case.
179    */
180   return (serialised.size <= alignment ||
181           (alignment & (gsize) serialised.data) == 0);
182 }
183 
184 /* < private >
185  * GVariantSerialisedFiller:
186  * @serialised: a #GVariantSerialised instance to fill
187  * @data: data from the children array
188  *
189  * This function is called back from g_variant_serialiser_needed_size()
190  * and g_variant_serialiser_serialise().  It fills in missing details
191  * from a partially-complete #GVariantSerialised.
192  *
193  * The @data parameter passed back to the function is one of the items
194  * that was passed to the serialiser in the @children array.  It
195  * represents a single child item of the container that is being
196  * serialised.  The information filled in to @serialised is the
197  * information for this child.
198  *
199  * If the @type_info field of @serialised is %NULL then the callback
200  * function must set it to the type information corresponding to the
201  * type of the child.  No reference should be added.  If it is non-%NULL
202  * then the callback should assert that it is equal to the actual type
203  * of the child.
204  *
205  * If the @size field is zero then the callback must fill it in with the
206  * required amount of space to store the serialised form of the child.
207  * If it is non-zero then the callback should assert that it is equal to
208  * the needed size of the child.
209  *
210  * If @data is non-%NULL then it points to a space that is properly
211  * aligned for and large enough to store the serialised data of the
212  * child.  The callback must store the serialised form of the child at
213  * @data.
214  *
215  * If the child value is another container then the callback will likely
216  * recurse back into the serialiser by calling
217  * g_variant_serialiser_needed_size() to determine @size and
218  * g_variant_serialiser_serialise() to write to @data.
219  */
220 
221 /* PART 1: Container types {{{1
222  *
223  * This section contains the serialiser implementation functions for
224  * each container type.
225  */
226 
227 /* Maybe {{{2
228  *
229  * Maybe types are handled depending on if the element type of the maybe
230  * type is a fixed-sized or variable-sized type.  Although all maybe
231  * types themselves are variable-sized types, herein, a maybe value with
232  * a fixed-sized element type is called a "fixed-sized maybe" for
233  * convenience and a maybe value with a variable-sized element type is
234  * called a "variable-sized maybe".
235  */
236 
237 /* Fixed-sized Maybe {{{3
238  *
239  * The size of a maybe value with a fixed-sized element type is either 0
240  * or equal to the fixed size of its element type.  The case where the
241  * size of the maybe value is zero corresponds to the "Nothing" case and
242  * the case where the size of the maybe value is equal to the fixed size
243  * of the element type corresponds to the "Just" case; in that case, the
244  * serialised data of the child value forms the entire serialised data
245  * of the maybe value.
246  *
247  * In the event that a fixed-sized maybe value is presented with a size
248  * that is not equal to the fixed size of the element type then the
249  * value must be taken to be "Nothing".
250  */
251 
252 static gsize
gvs_fixed_sized_maybe_n_children(GVariantSerialised value)253 gvs_fixed_sized_maybe_n_children (GVariantSerialised value)
254 {
255   gsize element_fixed_size;
256 
257   g_variant_type_info_query_element (value.type_info, NULL,
258                                      &element_fixed_size);
259 
260   return (element_fixed_size == value.size) ? 1 : 0;
261 }
262 
263 static GVariantSerialised
gvs_fixed_sized_maybe_get_child(GVariantSerialised value,gsize index_)264 gvs_fixed_sized_maybe_get_child (GVariantSerialised value,
265                                  gsize              index_)
266 {
267   /* the child has the same bounds as the
268    * container, so just update the type.
269    */
270   value.type_info = g_variant_type_info_element (value.type_info);
271   g_variant_type_info_ref (value.type_info);
272   value.depth++;
273   value.ordered_offsets_up_to = 0;
274   value.checked_offsets_up_to = 0;
275 
276   return value;
277 }
278 
279 static gsize
gvs_fixed_sized_maybe_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)280 gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
281                                    GVariantSerialisedFiller  gvs_filler,
282                                    const gpointer           *children,
283                                    gsize                     n_children)
284 {
285   if (n_children)
286     {
287       gsize element_fixed_size;
288 
289       g_variant_type_info_query_element (type_info, NULL,
290                                          &element_fixed_size);
291 
292       return element_fixed_size;
293     }
294   else
295     return 0;
296 }
297 
298 static void
gvs_fixed_sized_maybe_serialise(GVariantSerialised value,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)299 gvs_fixed_sized_maybe_serialise (GVariantSerialised        value,
300                                  GVariantSerialisedFiller  gvs_filler,
301                                  const gpointer           *children,
302                                  gsize                     n_children)
303 {
304   if (n_children)
305     {
306       GVariantSerialised child = { NULL, value.data, value.size, value.depth + 1, 0, 0 };
307 
308       gvs_filler (&child, children[0]);
309     }
310 }
311 
312 static gboolean
gvs_fixed_sized_maybe_is_normal(GVariantSerialised value)313 gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
314 {
315   if (value.size > 0)
316     {
317       gsize element_fixed_size;
318 
319       g_variant_type_info_query_element (value.type_info,
320                                          NULL, &element_fixed_size);
321 
322       if (value.size != element_fixed_size)
323         return FALSE;
324 
325       /* proper element size: "Just".  recurse to the child. */
326       value.type_info = g_variant_type_info_element (value.type_info);
327       value.depth++;
328       value.ordered_offsets_up_to = 0;
329       value.checked_offsets_up_to = 0;
330 
331       return g_variant_serialised_is_normal (value);
332     }
333 
334   /* size of 0: "Nothing" */
335   return TRUE;
336 }
337 
338 /* Variable-sized Maybe
339  *
340  * The size of a maybe value with a variable-sized element type is
341  * either 0 or strictly greater than 0.  The case where the size of the
342  * maybe value is zero corresponds to the "Nothing" case and the case
343  * where the size of the maybe value is greater than zero corresponds to
344  * the "Just" case; in that case, the serialised data of the child value
345  * forms the first part of the serialised data of the maybe value and is
346  * followed by a single zero byte.  This zero byte is always appended,
347  * regardless of any zero bytes that may already be at the end of the
348  * serialised ata of the child value.
349  */
350 
351 static gsize
gvs_variable_sized_maybe_n_children(GVariantSerialised value)352 gvs_variable_sized_maybe_n_children (GVariantSerialised value)
353 {
354   return (value.size > 0) ? 1 : 0;
355 }
356 
357 static GVariantSerialised
gvs_variable_sized_maybe_get_child(GVariantSerialised value,gsize index_)358 gvs_variable_sized_maybe_get_child (GVariantSerialised value,
359                                     gsize              index_)
360 {
361   /* remove the padding byte and update the type. */
362   value.type_info = g_variant_type_info_element (value.type_info);
363   g_variant_type_info_ref (value.type_info);
364   value.size--;
365 
366   /* if it's zero-sized then it may as well be NULL */
367   if (value.size == 0)
368     value.data = NULL;
369 
370   value.depth++;
371   value.ordered_offsets_up_to = 0;
372   value.checked_offsets_up_to = 0;
373 
374   return value;
375 }
376 
377 static gsize
gvs_variable_sized_maybe_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)378 gvs_variable_sized_maybe_needed_size (GVariantTypeInfo         *type_info,
379                                       GVariantSerialisedFiller  gvs_filler,
380                                       const gpointer           *children,
381                                       gsize                     n_children)
382 {
383   if (n_children)
384     {
385       GVariantSerialised child = { 0, };
386 
387       gvs_filler (&child, children[0]);
388 
389       return child.size + 1;
390     }
391   else
392     return 0;
393 }
394 
395 static void
gvs_variable_sized_maybe_serialise(GVariantSerialised value,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)396 gvs_variable_sized_maybe_serialise (GVariantSerialised        value,
397                                     GVariantSerialisedFiller  gvs_filler,
398                                     const gpointer           *children,
399                                     gsize                     n_children)
400 {
401   if (n_children)
402     {
403       GVariantSerialised child = { NULL, value.data, value.size - 1, value.depth + 1, 0, 0 };
404 
405       /* write the data for the child.  */
406       gvs_filler (&child, children[0]);
407       value.data[child.size] = '\0';
408     }
409 }
410 
411 static gboolean
gvs_variable_sized_maybe_is_normal(GVariantSerialised value)412 gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
413 {
414   if (value.size == 0)
415     return TRUE;
416 
417   if (value.data[value.size - 1] != '\0')
418     return FALSE;
419 
420   value.type_info = g_variant_type_info_element (value.type_info);
421   value.size--;
422   value.depth++;
423   value.ordered_offsets_up_to = 0;
424   value.checked_offsets_up_to = 0;
425 
426   return g_variant_serialised_is_normal (value);
427 }
428 
429 /* Arrays {{{2
430  *
431  * Just as with maybe types, array types are handled depending on if the
432  * element type of the array type is a fixed-sized or variable-sized
433  * type.  Similar to maybe types, for convenience, an array value with a
434  * fixed-sized element type is called a "fixed-sized array" and an array
435  * value with a variable-sized element type is called a "variable sized
436  * array".
437  */
438 
439 /* Fixed-sized Array {{{3
440  *
441  * For fixed sized arrays, the serialised data is simply a concatenation
442  * of the serialised data of each element, in order.  Since fixed-sized
443  * values always have a fixed size that is a multiple of their alignment
444  * requirement no extra padding is required.
445  *
446  * In the event that a fixed-sized array is presented with a size that
447  * is not an integer multiple of the element size then the value of the
448  * array must be taken as being empty.
449  */
450 
451 static gsize
gvs_fixed_sized_array_n_children(GVariantSerialised value)452 gvs_fixed_sized_array_n_children (GVariantSerialised value)
453 {
454   gsize element_fixed_size;
455 
456   g_variant_type_info_query_element (value.type_info, NULL,
457                                      &element_fixed_size);
458 
459   if (value.size % element_fixed_size == 0)
460     return value.size / element_fixed_size;
461 
462   return 0;
463 }
464 
465 static GVariantSerialised
gvs_fixed_sized_array_get_child(GVariantSerialised value,gsize index_)466 gvs_fixed_sized_array_get_child (GVariantSerialised value,
467                                  gsize              index_)
468 {
469   GVariantSerialised child = { 0, };
470 
471   child.type_info = g_variant_type_info_element (value.type_info);
472   g_variant_type_info_query (child.type_info, NULL, &child.size);
473   child.data = value.data + (child.size * index_);
474   g_variant_type_info_ref (child.type_info);
475   child.depth = value.depth + 1;
476 
477   return child;
478 }
479 
480 static gsize
gvs_fixed_sized_array_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)481 gvs_fixed_sized_array_needed_size (GVariantTypeInfo         *type_info,
482                                    GVariantSerialisedFiller  gvs_filler,
483                                    const gpointer           *children,
484                                    gsize                     n_children)
485 {
486   gsize element_fixed_size;
487 
488   g_variant_type_info_query_element (type_info, NULL, &element_fixed_size);
489 
490   return element_fixed_size * n_children;
491 }
492 
493 static void
gvs_fixed_sized_array_serialise(GVariantSerialised value,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)494 gvs_fixed_sized_array_serialise (GVariantSerialised        value,
495                                  GVariantSerialisedFiller  gvs_filler,
496                                  const gpointer           *children,
497                                  gsize                     n_children)
498 {
499   GVariantSerialised child = { 0, };
500   gsize i;
501 
502   child.type_info = g_variant_type_info_element (value.type_info);
503   g_variant_type_info_query (child.type_info, NULL, &child.size);
504   child.data = value.data;
505   child.depth = value.depth + 1;
506 
507   for (i = 0; i < n_children; i++)
508     {
509       gvs_filler (&child, children[i]);
510       child.data += child.size;
511     }
512 }
513 
514 static gboolean
gvs_fixed_sized_array_is_normal(GVariantSerialised value)515 gvs_fixed_sized_array_is_normal (GVariantSerialised value)
516 {
517   GVariantSerialised child = { 0, };
518 
519   child.type_info = g_variant_type_info_element (value.type_info);
520   g_variant_type_info_query (child.type_info, NULL, &child.size);
521   child.depth = value.depth + 1;
522 
523   if (value.size % child.size != 0)
524     return FALSE;
525 
526   for (child.data = value.data;
527        child.data < value.data + value.size;
528        child.data += child.size)
529     {
530       if (!g_variant_serialised_is_normal (child))
531         return FALSE;
532     }
533 
534   return TRUE;
535 }
536 
537 /* Variable-sized Array {{{3
538  *
539  * Variable sized arrays, containing variable-sized elements, must be
540  * able to determine the boundaries between the elements.  The items
541  * cannot simply be concatenated.  Additionally, we are faced with the
542  * fact that non-fixed-sized values do not necessarily have a size that
543  * is a multiple of their alignment requirement, so we may need to
544  * insert zero-filled padding.
545  *
546  * While it is possible to find the start of an item by starting from
547  * the end of the item before it and padding for alignment, it is not
548  * generally possible to do the reverse operation.  For this reason, we
549  * record the end point of each element in the array.
550  *
551  * GVariant works in terms of "offsets".  An offset is a pointer to a
552  * boundary between two bytes.  In 4 bytes of serialised data, there
553  * would be 5 possible offsets: one at the start ('0'), one between each
554  * pair of adjacent bytes ('1', '2', '3') and one at the end ('4').
555  *
556  * The numeric value of an offset is an unsigned integer given relative
557  * to the start of the serialised data of the array.  Offsets are always
558  * stored in little endian byte order and are always only as big as they
559  * need to be.  For example, in 255 bytes of serialised data, there are
560  * 256 offsets.  All possibilities can be stored in an 8 bit unsigned
561  * integer.  In 256 bytes of serialised data, however, there are 257
562  * possible offsets so 16 bit integers must be used.  The size of an
563  * offset is always a power of 2.
564  *
565  * The offsets are stored at the end of the serialised data of the
566  * array.  They are simply concatenated on without any particular
567  * alignment.  The size of the offsets is included in the size of the
568  * serialised data for purposes of determining the size of the offsets.
569  * This presents a possibly ambiguity; in certain cases, a particular
570  * value of array could have two different serialised forms.
571  *
572  * Imagine an array containing a single string of 253 bytes in length
573  * (so, 254 bytes including the nul terminator).  Now the offset must be
574  * written.  If an 8 bit offset is written, it will bring the size of
575  * the array's serialised data to 255 -- which means that the use of an
576  * 8 bit offset was valid.  If a 16 bit offset is used then the total
577  * size of the array will be 256 -- which means that the use of a 16 bit
578  * offset was valid.  Although both of these will be accepted by the
579  * deserialiser, only the smaller of the two is considered to be in
580  * normal form and that is the one that the serialiser must produce.
581  */
582 
583 /* bytes may be NULL if (size == 0). */
584 static inline gsize
gvs_read_unaligned_le(guchar * bytes,guint size)585 gvs_read_unaligned_le (guchar *bytes,
586                        guint   size)
587 {
588   union
589   {
590     guchar bytes[GLIB_SIZEOF_SIZE_T];
591     gsize integer;
592   } tmpvalue;
593 
594   tmpvalue.integer = 0;
595   if (bytes != NULL)
596     memcpy (&tmpvalue.bytes, bytes, size);
597 
598   return GSIZE_FROM_LE (tmpvalue.integer);
599 }
600 
601 static inline void
gvs_write_unaligned_le(guchar * bytes,gsize value,guint size)602 gvs_write_unaligned_le (guchar *bytes,
603                         gsize   value,
604                         guint   size)
605 {
606   union
607   {
608     guchar bytes[GLIB_SIZEOF_SIZE_T];
609     gsize integer;
610   } tmpvalue;
611 
612   tmpvalue.integer = GSIZE_TO_LE (value);
613   memcpy (bytes, &tmpvalue.bytes, size);
614 }
615 
616 static guint
gvs_get_offset_size(gsize size)617 gvs_get_offset_size (gsize size)
618 {
619   if (size > G_MAXUINT32)
620     return 8;
621 
622   else if (size > G_MAXUINT16)
623     return 4;
624 
625   else if (size > G_MAXUINT8)
626     return 2;
627 
628   else if (size > 0)
629     return 1;
630 
631   return 0;
632 }
633 
634 static gsize
gvs_calculate_total_size(gsize body_size,gsize offsets)635 gvs_calculate_total_size (gsize body_size,
636                           gsize offsets)
637 {
638   if (body_size + 1 * offsets <= G_MAXUINT8)
639     return body_size + 1 * offsets;
640 
641   if (body_size + 2 * offsets <= G_MAXUINT16)
642     return body_size + 2 * offsets;
643 
644   if (body_size + 4 * offsets <= G_MAXUINT32)
645     return body_size + 4 * offsets;
646 
647   return body_size + 8 * offsets;
648 }
649 
650 struct Offsets
651 {
652   gsize     data_size;
653 
654   guchar   *array;
655   gsize     length;
656   guint     offset_size;
657 
658   gboolean  is_normal;
659 };
660 
661 static gsize
gvs_offsets_get_offset_n(struct Offsets * offsets,gsize n)662 gvs_offsets_get_offset_n (struct Offsets *offsets,
663                           gsize           n)
664 {
665   return gvs_read_unaligned_le (
666       offsets->array + (offsets->offset_size * n), offsets->offset_size);
667 }
668 
669 static struct Offsets
gvs_variable_sized_array_get_frame_offsets(GVariantSerialised value)670 gvs_variable_sized_array_get_frame_offsets (GVariantSerialised value)
671 {
672   struct Offsets out = { 0, };
673   gsize offsets_array_size;
674   gsize last_end;
675 
676   if (value.size == 0)
677     {
678       out.is_normal = TRUE;
679       return out;
680     }
681 
682   out.offset_size = gvs_get_offset_size (value.size);
683   last_end = gvs_read_unaligned_le (value.data + value.size - out.offset_size,
684                                     out.offset_size);
685 
686   if (last_end > value.size)
687     return out;  /* offsets not normal */
688 
689   offsets_array_size = value.size - last_end;
690 
691   if (offsets_array_size % out.offset_size)
692     return out;  /* offsets not normal */
693 
694   out.data_size = last_end;
695   out.array = value.data + last_end;
696   out.length = offsets_array_size / out.offset_size;
697 
698   if (out.length > 0 && gvs_calculate_total_size (last_end, out.length) != value.size)
699     return out;  /* offset size not minimal */
700 
701   out.is_normal = TRUE;
702 
703   return out;
704 }
705 
706 static gsize
gvs_variable_sized_array_n_children(GVariantSerialised value)707 gvs_variable_sized_array_n_children (GVariantSerialised value)
708 {
709   return gvs_variable_sized_array_get_frame_offsets (value).length;
710 }
711 
712 /* Find the index of the first out-of-order element in @data, assuming that
713  * @data is an array of elements of given @type, starting at index @start and
714  * containing a further @len-@start elements. */
715 #define DEFINE_FIND_UNORDERED(type) \
716   static gsize \
717   find_unordered_##type (const guint8 *data, gsize start, gsize len) \
718   { \
719     gsize off; \
720     type current, previous; \
721     \
722     memcpy (&previous, data + start * sizeof (current), sizeof (current)); \
723     for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \
724       { \
725         memcpy (&current, data + off, sizeof (current)); \
726         if (current < previous) \
727           break; \
728         previous = current; \
729       } \
730     return off / sizeof (current) - 1; \
731   }
732 
733 DEFINE_FIND_UNORDERED (guint8);
734 DEFINE_FIND_UNORDERED (guint16);
735 DEFINE_FIND_UNORDERED (guint32);
736 DEFINE_FIND_UNORDERED (guint64);
737 
738 static GVariantSerialised
gvs_variable_sized_array_get_child(GVariantSerialised value,gsize index_)739 gvs_variable_sized_array_get_child (GVariantSerialised value,
740                                     gsize              index_)
741 {
742   GVariantSerialised child = { 0, };
743 
744   struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
745 
746   gsize start;
747   gsize end;
748 
749   child.type_info = g_variant_type_info_element (value.type_info);
750   g_variant_type_info_ref (child.type_info);
751   child.depth = value.depth + 1;
752 
753   /* If the requested @index_ is beyond the set of indices whose framing offsets
754    * have been checked, check the remaining offsets to see whether they’re
755    * normal (in order, no overlapping array elements).
756    *
757    * Don’t bother checking if the highest known-good offset is lower than the
758    * highest checked offset, as that means there’s an invalid element at that
759    * index, so there’s no need to check further. */
760   if (index_ > value.checked_offsets_up_to &&
761       value.ordered_offsets_up_to == value.checked_offsets_up_to)
762     {
763       switch (offsets.offset_size)
764         {
765         case 1:
766           {
767             value.ordered_offsets_up_to = find_unordered_guint8 (
768                 offsets.array, value.checked_offsets_up_to, index_ + 1);
769             break;
770           }
771         case 2:
772           {
773             value.ordered_offsets_up_to = find_unordered_guint16 (
774                 offsets.array, value.checked_offsets_up_to, index_ + 1);
775             break;
776           }
777         case 4:
778           {
779             value.ordered_offsets_up_to = find_unordered_guint32 (
780                 offsets.array, value.checked_offsets_up_to, index_ + 1);
781             break;
782           }
783         case 8:
784           {
785             value.ordered_offsets_up_to = find_unordered_guint64 (
786                 offsets.array, value.checked_offsets_up_to, index_ + 1);
787             break;
788           }
789         default:
790           /* gvs_get_offset_size() only returns maximum 8 */
791           g_assert_not_reached ();
792         }
793 
794       value.checked_offsets_up_to = index_;
795     }
796 
797   if (index_ > value.ordered_offsets_up_to)
798     {
799       /* Offsets are invalid somewhere, so return an empty child. */
800       return child;
801     }
802 
803   if (index_ > 0)
804     {
805       guint alignment;
806 
807       start = gvs_offsets_get_offset_n (&offsets, index_ - 1);
808 
809       g_variant_type_info_query (child.type_info, &alignment, NULL);
810       start += (-start) & alignment;
811     }
812   else
813     start = 0;
814 
815   end = gvs_offsets_get_offset_n (&offsets, index_);
816 
817   if (start < end && end <= value.size && end <= offsets.data_size)
818     {
819       child.data = value.data + start;
820       child.size = end - start;
821     }
822 
823   return child;
824 }
825 
826 static gsize
gvs_variable_sized_array_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)827 gvs_variable_sized_array_needed_size (GVariantTypeInfo         *type_info,
828                                       GVariantSerialisedFiller  gvs_filler,
829                                       const gpointer           *children,
830                                       gsize                     n_children)
831 {
832   guint alignment;
833   gsize offset;
834   gsize i;
835 
836   g_variant_type_info_query (type_info, &alignment, NULL);
837   offset = 0;
838 
839   for (i = 0; i < n_children; i++)
840     {
841       GVariantSerialised child = { 0, };
842 
843       offset += (-offset) & alignment;
844       gvs_filler (&child, children[i]);
845       offset += child.size;
846     }
847 
848   return gvs_calculate_total_size (offset, n_children);
849 }
850 
851 static void
gvs_variable_sized_array_serialise(GVariantSerialised value,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)852 gvs_variable_sized_array_serialise (GVariantSerialised        value,
853                                     GVariantSerialisedFiller  gvs_filler,
854                                     const gpointer           *children,
855                                     gsize                     n_children)
856 {
857   guchar *offset_ptr;
858   gsize offset_size;
859   guint alignment;
860   gsize offset;
861   gsize i;
862 
863   g_variant_type_info_query (value.type_info, &alignment, NULL);
864   offset_size = gvs_get_offset_size (value.size);
865   offset = 0;
866 
867   offset_ptr = value.data + value.size - offset_size * n_children;
868 
869   for (i = 0; i < n_children; i++)
870     {
871       GVariantSerialised child = { 0, };
872 
873       while (offset & alignment)
874         value.data[offset++] = '\0';
875 
876       child.data = value.data + offset;
877       gvs_filler (&child, children[i]);
878       offset += child.size;
879 
880       gvs_write_unaligned_le (offset_ptr, offset, offset_size);
881       offset_ptr += offset_size;
882     }
883 }
884 
885 static gboolean
gvs_variable_sized_array_is_normal(GVariantSerialised value)886 gvs_variable_sized_array_is_normal (GVariantSerialised value)
887 {
888   GVariantSerialised child = { 0, };
889   guint alignment;
890   gsize offset;
891   gsize i;
892 
893   struct Offsets offsets = gvs_variable_sized_array_get_frame_offsets (value);
894 
895   if (!offsets.is_normal)
896     return FALSE;
897 
898   if (value.size != 0 && offsets.length == 0)
899     return FALSE;
900 
901   child.type_info = g_variant_type_info_element (value.type_info);
902   g_variant_type_info_query (child.type_info, &alignment, NULL);
903   child.depth = value.depth + 1;
904   offset = 0;
905 
906   for (i = 0; i < offsets.length; i++)
907     {
908       gsize this_end;
909 
910       this_end = gvs_read_unaligned_le (offsets.array + offsets.offset_size * i,
911                                         offsets.offset_size);
912 
913       if (this_end < offset || this_end > offsets.data_size)
914         return FALSE;
915 
916       while (offset & alignment)
917         {
918           if (!(offset < this_end && value.data[offset] == '\0'))
919             return FALSE;
920           offset++;
921         }
922 
923       child.data = value.data + offset;
924       child.size = this_end - offset;
925 
926       if (child.size == 0)
927         child.data = NULL;
928 
929       if (!g_variant_serialised_is_normal (child))
930         return FALSE;
931 
932       offset = this_end;
933     }
934 
935   g_assert (offset == offsets.data_size);
936 
937   /* All offsets have now been checked. */
938   value.ordered_offsets_up_to = G_MAXSIZE;
939   value.checked_offsets_up_to = G_MAXSIZE;
940 
941   return TRUE;
942 }
943 
944 /* Tuples {{{2
945  *
946  * Since tuples can contain a mix of variable- and fixed-sized items,
947  * they are, in terms of serialisation, a hybrid of variable-sized and
948  * fixed-sized arrays.
949  *
950  * Offsets are only stored for variable-sized items.  Also, since the
951  * number of items in a tuple is known from its type, we are able to
952  * know exactly how many offsets to expect in the serialised data (and
953  * therefore how much space is taken up by the offset array).  This
954  * means that we know where the end of the serialised data for the last
955  * item is -- we can just subtract the size of the offset array from the
956  * total size of the tuple.  For this reason, the last item in the tuple
957  * doesn't need an offset stored.
958  *
959  * Tuple offsets are stored in reverse.  This design choice allows
960  * iterator-based deserialisers to be more efficient.
961  *
962  * Most of the "heavy lifting" here is handled by the GVariantTypeInfo
963  * for the tuple.  See the notes in gvarianttypeinfo.h.
964  */
965 
966 /* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that
967  * condition may not hold true for invalid serialised variants. The caller is
968  * responsible for checking the returned values and handling invalid ones
969  * appropriately. */
970 static void
gvs_tuple_get_member_bounds(GVariantSerialised value,gsize index_,gsize offset_size,gsize * out_member_start,gsize * out_member_end)971 gvs_tuple_get_member_bounds (GVariantSerialised  value,
972                              gsize               index_,
973                              gsize               offset_size,
974                              gsize              *out_member_start,
975                              gsize              *out_member_end)
976 {
977   const GVariantMemberInfo *member_info;
978   gsize member_start, member_end;
979 
980   member_info = g_variant_type_info_member_info (value.type_info, index_);
981 
982   if (member_info->i + 1 &&
983       offset_size * (member_info->i + 1) <= value.size)
984     member_start = gvs_read_unaligned_le (value.data + value.size -
985                                           offset_size * (member_info->i + 1),
986                                           offset_size);
987   else
988     member_start = 0;
989 
990   member_start += member_info->a;
991   member_start &= member_info->b;
992   member_start |= member_info->c;
993 
994   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST &&
995       offset_size * (member_info->i + 1) <= value.size)
996     member_end = value.size - offset_size * (member_info->i + 1);
997 
998   else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
999     {
1000       gsize fixed_size;
1001 
1002       g_variant_type_info_query (member_info->type_info, NULL, &fixed_size);
1003       member_end = member_start + fixed_size;
1004     }
1005 
1006   else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET &&
1007            offset_size * (member_info->i + 2) <= value.size)
1008     member_end = gvs_read_unaligned_le (value.data + value.size -
1009                                         offset_size * (member_info->i + 2),
1010                                         offset_size);
1011 
1012   else  /* invalid */
1013     member_end = G_MAXSIZE;
1014 
1015   if (out_member_start != NULL)
1016     *out_member_start = member_start;
1017   if (out_member_end != NULL)
1018     *out_member_end = member_end;
1019 }
1020 
1021 static gsize
gvs_tuple_n_children(GVariantSerialised value)1022 gvs_tuple_n_children (GVariantSerialised value)
1023 {
1024   return g_variant_type_info_n_members (value.type_info);
1025 }
1026 
1027 static GVariantSerialised
gvs_tuple_get_child(GVariantSerialised value,gsize index_)1028 gvs_tuple_get_child (GVariantSerialised value,
1029                      gsize              index_)
1030 {
1031   const GVariantMemberInfo *member_info;
1032   GVariantSerialised child = { 0, };
1033   gsize offset_size;
1034   gsize start, end, last_end;
1035 
1036   member_info = g_variant_type_info_member_info (value.type_info, index_);
1037   child.type_info = g_variant_type_info_ref (member_info->type_info);
1038   child.depth = value.depth + 1;
1039   offset_size = gvs_get_offset_size (value.size);
1040 
1041   /* Ensure the size is set for fixed-sized children, or
1042    * g_variant_serialised_check() will fail, even if we return
1043    * (child.data == NULL) to indicate an error. */
1044   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
1045     g_variant_type_info_query (child.type_info, NULL, &child.size);
1046 
1047   /* tuples are the only (potentially) fixed-sized containers, so the
1048    * only ones that have to deal with the possibility of having %NULL
1049    * data with a non-zero %size if errors occurred elsewhere.
1050    */
1051   if G_UNLIKELY (value.data == NULL && value.size != 0)
1052     {
1053       /* this can only happen in fixed-sized tuples,
1054        * so the child must also be fixed sized.
1055        */
1056       g_assert (child.size != 0);
1057       child.data = NULL;
1058 
1059       return child;
1060     }
1061 
1062   /* If the requested @index_ is beyond the set of indices whose framing offsets
1063    * have been checked, check the remaining offsets to see whether they’re
1064    * normal (in order, no overlapping tuple elements).
1065    *
1066    * Unlike the checks in gvs_variable_sized_array_get_child(), we have to check
1067    * all the tuple *elements* here, not just all the framing offsets, since
1068    * tuples contain a mix of elements which use framing offsets and ones which
1069    * don’t. None of them are allowed to overlap. */
1070   if (index_ > value.checked_offsets_up_to &&
1071       value.ordered_offsets_up_to == value.checked_offsets_up_to)
1072     {
1073       gsize i, prev_i_end = 0;
1074 
1075       if (value.checked_offsets_up_to > 0)
1076         gvs_tuple_get_member_bounds (value, value.checked_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
1077 
1078       for (i = value.checked_offsets_up_to; i <= index_; i++)
1079         {
1080           gsize i_start, i_end;
1081 
1082           gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end);
1083 
1084           if (i_start > i_end || i_start < prev_i_end || i_end > value.size)
1085             break;
1086 
1087           prev_i_end = i_end;
1088         }
1089 
1090       value.ordered_offsets_up_to = i - 1;
1091       value.checked_offsets_up_to = index_;
1092     }
1093 
1094   if (index_ > value.ordered_offsets_up_to)
1095     {
1096       /* Offsets are invalid somewhere, so return an empty child. */
1097       return child;
1098     }
1099 
1100   if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1101     {
1102       if (offset_size * (member_info->i + 2) > value.size)
1103         return child;
1104     }
1105   else
1106     {
1107       if (offset_size * (member_info->i + 1) > value.size)
1108         return child;
1109     }
1110 
1111   /* The child should not extend into the offset table. */
1112   gvs_tuple_get_member_bounds (value, index_, offset_size, &start, &end);
1113   gvs_tuple_get_member_bounds (value, g_variant_type_info_n_members (value.type_info) - 1, offset_size, NULL, &last_end);
1114 
1115   if (start < end && end <= value.size && end <= last_end)
1116     {
1117       child.data = value.data + start;
1118       child.size = end - start;
1119     }
1120 
1121   return child;
1122 }
1123 
1124 static gsize
gvs_tuple_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)1125 gvs_tuple_needed_size (GVariantTypeInfo         *type_info,
1126                        GVariantSerialisedFiller  gvs_filler,
1127                        const gpointer           *children,
1128                        gsize                     n_children)
1129 {
1130   const GVariantMemberInfo *member_info = NULL;
1131   gsize fixed_size;
1132   gsize offset;
1133   gsize i;
1134 
1135   g_variant_type_info_query (type_info, NULL, &fixed_size);
1136 
1137   if (fixed_size)
1138     return fixed_size;
1139 
1140   offset = 0;
1141 
1142   for (i = 0; i < n_children; i++)
1143     {
1144       guint alignment;
1145 
1146       member_info = g_variant_type_info_member_info (type_info, i);
1147       g_variant_type_info_query (member_info->type_info,
1148                                  &alignment, &fixed_size);
1149       offset += (-offset) & alignment;
1150 
1151       if (fixed_size)
1152         offset += fixed_size;
1153       else
1154         {
1155           GVariantSerialised child = { 0, };
1156 
1157           gvs_filler (&child, children[i]);
1158           offset += child.size;
1159         }
1160     }
1161 
1162   return gvs_calculate_total_size (offset, member_info->i + 1);
1163 }
1164 
1165 static void
gvs_tuple_serialise(GVariantSerialised value,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)1166 gvs_tuple_serialise (GVariantSerialised        value,
1167                      GVariantSerialisedFiller  gvs_filler,
1168                      const gpointer           *children,
1169                      gsize                     n_children)
1170 {
1171   gsize offset_size;
1172   gsize offset;
1173   gsize i;
1174 
1175   offset_size = gvs_get_offset_size (value.size);
1176   offset = 0;
1177 
1178   for (i = 0; i < n_children; i++)
1179     {
1180       const GVariantMemberInfo *member_info;
1181       GVariantSerialised child = { 0, };
1182       guint alignment;
1183 
1184       member_info = g_variant_type_info_member_info (value.type_info, i);
1185       g_variant_type_info_query (member_info->type_info, &alignment, NULL);
1186 
1187       while (offset & alignment)
1188         value.data[offset++] = '\0';
1189 
1190       child.data = value.data + offset;
1191       gvs_filler (&child, children[i]);
1192       offset += child.size;
1193 
1194       if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
1195         {
1196           value.size -= offset_size;
1197           gvs_write_unaligned_le (value.data + value.size,
1198                                   offset, offset_size);
1199         }
1200     }
1201 
1202   while (offset < value.size)
1203     value.data[offset++] = '\0';
1204 }
1205 
1206 static gboolean
gvs_tuple_is_normal(GVariantSerialised value)1207 gvs_tuple_is_normal (GVariantSerialised value)
1208 {
1209   guint offset_size;
1210   gsize offset_ptr;
1211   gsize length;
1212   gsize offset;
1213   gsize i;
1214   gsize offset_table_size;
1215 
1216   /* as per the comment in gvs_tuple_get_child() */
1217   if G_UNLIKELY (value.data == NULL && value.size != 0)
1218     return FALSE;
1219 
1220   offset_size = gvs_get_offset_size (value.size);
1221   length = g_variant_type_info_n_members (value.type_info);
1222   offset_ptr = value.size;
1223   offset = 0;
1224 
1225   for (i = 0; i < length; i++)
1226     {
1227       const GVariantMemberInfo *member_info;
1228       GVariantSerialised child = { 0, };
1229       gsize fixed_size;
1230       guint alignment;
1231       gsize end;
1232 
1233       member_info = g_variant_type_info_member_info (value.type_info, i);
1234       child.type_info = member_info->type_info;
1235       child.depth = value.depth + 1;
1236 
1237       g_variant_type_info_query (child.type_info, &alignment, &fixed_size);
1238 
1239       while (offset & alignment)
1240         {
1241           if (offset > value.size || value.data[offset] != '\0')
1242             return FALSE;
1243           offset++;
1244         }
1245 
1246       child.data = value.data + offset;
1247 
1248       switch (member_info->ending_type)
1249         {
1250         case G_VARIANT_MEMBER_ENDING_FIXED:
1251           end = offset + fixed_size;
1252           break;
1253 
1254         case G_VARIANT_MEMBER_ENDING_LAST:
1255           end = offset_ptr;
1256           break;
1257 
1258         case G_VARIANT_MEMBER_ENDING_OFFSET:
1259           if (offset_ptr < offset_size)
1260             return FALSE;
1261 
1262           offset_ptr -= offset_size;
1263 
1264           if (offset_ptr < offset)
1265             return FALSE;
1266 
1267           end = gvs_read_unaligned_le (value.data + offset_ptr, offset_size);
1268           break;
1269 
1270         default:
1271           g_assert_not_reached ();
1272         }
1273 
1274       if (end < offset || end > offset_ptr)
1275         return FALSE;
1276 
1277       child.size = end - offset;
1278 
1279       if (child.size == 0)
1280         child.data = NULL;
1281 
1282       if (!g_variant_serialised_is_normal (child))
1283         return FALSE;
1284 
1285       offset = end;
1286     }
1287 
1288   /* All element bounds have been checked above. */
1289   value.ordered_offsets_up_to = G_MAXSIZE;
1290   value.checked_offsets_up_to = G_MAXSIZE;
1291 
1292   {
1293     gsize fixed_size;
1294     guint alignment;
1295 
1296     g_variant_type_info_query (value.type_info, &alignment, &fixed_size);
1297 
1298     if (fixed_size)
1299       {
1300         g_assert (fixed_size == value.size);
1301         g_assert (offset_ptr == value.size);
1302 
1303         if (i == 0)
1304           {
1305             if (value.data[offset++] != '\0')
1306               return FALSE;
1307           }
1308         else
1309           {
1310             while (offset & alignment)
1311               if (value.data[offset++] != '\0')
1312                 return FALSE;
1313           }
1314 
1315         g_assert (offset == value.size);
1316       }
1317   }
1318 
1319   /* @offset_ptr has been counting backwards from the end of the variant, to
1320    * find the beginning of the offset table. @offset has been counting forwards
1321    * from the beginning of the variant to find the end of the data. They should
1322    * have met in the middle. */
1323   if (offset_ptr != offset)
1324     return FALSE;
1325 
1326   offset_table_size = value.size - offset_ptr;
1327   if (value.size > 0 &&
1328       gvs_calculate_total_size (offset, offset_table_size / offset_size) != value.size)
1329     return FALSE;  /* offset size not minimal */
1330 
1331   return TRUE;
1332 }
1333 
1334 /* Variants {{{2
1335  *
1336  * Variants are stored by storing the serialised data of the child,
1337  * followed by a '\0' character, followed by the type string of the
1338  * child.
1339  *
1340  * In the case that a value is presented that contains no '\0'
1341  * character, or doesn't have a single well-formed definite type string
1342  * following that character, the variant must be taken as containing the
1343  * unit tuple: ().
1344  */
1345 
1346 static inline gsize
gvs_variant_n_children(GVariantSerialised value)1347 gvs_variant_n_children (GVariantSerialised value)
1348 {
1349   return 1;
1350 }
1351 
1352 static inline GVariantSerialised
gvs_variant_get_child(GVariantSerialised value,gsize index_)1353 gvs_variant_get_child (GVariantSerialised value,
1354                        gsize              index_)
1355 {
1356   GVariantSerialised child = { 0, };
1357 
1358   /* NOTE: not O(1) and impossible for it to be... */
1359   if (value.size)
1360     {
1361       /* find '\0' character */
1362       for (child.size = value.size - 1; child.size; child.size--)
1363         if (value.data[child.size] == '\0')
1364           break;
1365 
1366       /* ensure we didn't just hit the start of the string */
1367       if (value.data[child.size] == '\0')
1368         {
1369           const gchar *type_string = (gchar *) &value.data[child.size + 1];
1370           const gchar *limit = (gchar *) &value.data[value.size];
1371           const gchar *end;
1372 
1373           if (g_variant_type_string_scan (type_string, limit, &end) &&
1374               end == limit)
1375             {
1376               const GVariantType *type = (GVariantType *) type_string;
1377 
1378               if (g_variant_type_is_definite (type))
1379                 {
1380                   gsize fixed_size;
1381                   gsize child_type_depth;
1382 
1383                   child.type_info = g_variant_type_info_get (type);
1384                   child.depth = value.depth + 1;
1385 
1386                   if (child.size != 0)
1387                     /* only set to non-%NULL if size > 0 */
1388                     child.data = value.data;
1389 
1390                   g_variant_type_info_query (child.type_info,
1391                                              NULL, &fixed_size);
1392                   child_type_depth = g_variant_type_info_query_depth (child.type_info);
1393 
1394                   if ((!fixed_size || fixed_size == child.size) &&
1395                       value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth)
1396                     return child;
1397 
1398                   g_variant_type_info_unref (child.type_info);
1399                 }
1400             }
1401         }
1402     }
1403 
1404   child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
1405   child.data = NULL;
1406   child.size = 1;
1407   child.depth = value.depth + 1;
1408 
1409   return child;
1410 }
1411 
1412 static inline gsize
gvs_variant_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)1413 gvs_variant_needed_size (GVariantTypeInfo         *type_info,
1414                          GVariantSerialisedFiller  gvs_filler,
1415                          const gpointer           *children,
1416                          gsize                     n_children)
1417 {
1418   GVariantSerialised child = { 0, };
1419   const gchar *type_string;
1420 
1421   gvs_filler (&child, children[0]);
1422   type_string = g_variant_type_info_get_type_string (child.type_info);
1423 
1424   return child.size + 1 + strlen (type_string);
1425 }
1426 
1427 static inline void
gvs_variant_serialise(GVariantSerialised value,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)1428 gvs_variant_serialise (GVariantSerialised        value,
1429                        GVariantSerialisedFiller  gvs_filler,
1430                        const gpointer           *children,
1431                        gsize                     n_children)
1432 {
1433   GVariantSerialised child = { 0, };
1434   const gchar *type_string;
1435 
1436   child.data = value.data;
1437 
1438   gvs_filler (&child, children[0]);
1439   type_string = g_variant_type_info_get_type_string (child.type_info);
1440   value.data[child.size] = '\0';
1441   memcpy (value.data + child.size + 1, type_string, strlen (type_string));
1442 }
1443 
1444 static inline gboolean
gvs_variant_is_normal(GVariantSerialised value)1445 gvs_variant_is_normal (GVariantSerialised value)
1446 {
1447   GVariantSerialised child;
1448   gboolean normal;
1449   gsize child_type_depth;
1450 
1451   child = gvs_variant_get_child (value, 0);
1452   child_type_depth = g_variant_type_info_query_depth (child.type_info);
1453 
1454   normal = (value.depth < G_VARIANT_MAX_RECURSION_DEPTH - child_type_depth) &&
1455            (child.data != NULL || child.size == 0) &&
1456            g_variant_serialised_is_normal (child);
1457 
1458   g_variant_type_info_unref (child.type_info);
1459 
1460   return normal;
1461 }
1462 
1463 
1464 
1465 /* PART 2: Serialiser API {{{1
1466  *
1467  * This is the implementation of the API of the serialiser as advertised
1468  * in gvariant-serialiser.h.
1469  */
1470 
1471 /* Dispatch Utilities {{{2
1472  *
1473  * These macros allow a given function (for example,
1474  * g_variant_serialiser_serialise) to be dispatched to the appropriate
1475  * type-specific function above (fixed/variable-sized maybe,
1476  * fixed/variable-sized array, tuple or variant).
1477  */
1478 #define DISPATCH_FIXED(type_info, before, after) \
1479   {                                                     \
1480     gsize fixed_size;                                   \
1481                                                         \
1482     g_variant_type_info_query_element (type_info, NULL, \
1483                                        &fixed_size);    \
1484                                                         \
1485     if (fixed_size)                                     \
1486       {                                                 \
1487         before ## fixed_sized ## after                  \
1488       }                                                 \
1489     else                                                \
1490       {                                                 \
1491         before ## variable_sized ## after               \
1492       }                                                 \
1493   }
1494 
1495 #define DISPATCH_CASES(type_info, before, after) \
1496   switch (g_variant_type_info_get_type_char (type_info))        \
1497     {                                                           \
1498       case G_VARIANT_TYPE_INFO_CHAR_MAYBE:                      \
1499         DISPATCH_FIXED (type_info, before, _maybe ## after)     \
1500                                                                 \
1501       case G_VARIANT_TYPE_INFO_CHAR_ARRAY:                      \
1502         DISPATCH_FIXED (type_info, before, _array ## after)     \
1503                                                                 \
1504       case G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY:                 \
1505       case G_VARIANT_TYPE_INFO_CHAR_TUPLE:                      \
1506         {                                                       \
1507           before ## tuple ## after                              \
1508         }                                                       \
1509                                                                 \
1510       case G_VARIANT_TYPE_INFO_CHAR_VARIANT:                    \
1511         {                                                       \
1512           before ## variant ## after                            \
1513         }                                                       \
1514     }
1515 
1516 /* Serialiser entry points {{{2
1517  *
1518  * These are the functions that are called in order for the serialiser
1519  * to do its thing.
1520  */
1521 
1522 /* < private >
1523  * g_variant_serialised_n_children:
1524  * @serialised: a #GVariantSerialised
1525  *
1526  * For serialised data that represents a container value (maybes,
1527  * tuples, arrays, variants), determine how many child items are inside
1528  * that container.
1529  *
1530  * Returns: the number of children
1531  */
1532 gsize
g_variant_serialised_n_children(GVariantSerialised serialised)1533 g_variant_serialised_n_children (GVariantSerialised serialised)
1534 {
1535   g_assert (g_variant_serialised_check (serialised));
1536 
1537   DISPATCH_CASES (serialised.type_info,
1538 
1539                   return gvs_/**/,/**/_n_children (serialised);
1540 
1541                  )
1542   g_assert_not_reached ();
1543 }
1544 
1545 /* < private >
1546  * g_variant_serialised_get_child:
1547  * @serialised: a #GVariantSerialised
1548  * @index_: the index of the child to fetch
1549  *
1550  * Extracts a child from a serialised data representing a container
1551  * value.
1552  *
1553  * It is an error to call this function with an index out of bounds.
1554  *
1555  * If the result .data == %NULL and .size > 0 then there has been an
1556  * error extracting the requested fixed-sized value.  This number of
1557  * zero bytes needs to be allocated instead.
1558  *
1559  * In the case that .data == %NULL and .size == 0 then a zero-sized
1560  * item of a variable-sized type is being returned.
1561  *
1562  * .data is never non-%NULL if size is 0.
1563  *
1564  * Returns: a #GVariantSerialised for the child
1565  */
1566 GVariantSerialised
g_variant_serialised_get_child(GVariantSerialised serialised,gsize index_)1567 g_variant_serialised_get_child (GVariantSerialised serialised,
1568                                 gsize              index_)
1569 {
1570   GVariantSerialised child;
1571 
1572   g_assert (g_variant_serialised_check (serialised));
1573 
1574   if G_LIKELY (index_ < g_variant_serialised_n_children (serialised))
1575     {
1576       DISPATCH_CASES (serialised.type_info,
1577 
1578                       child = gvs_/**/,/**/_get_child (serialised, index_);
1579                       g_assert (child.size || child.data == NULL);
1580                       g_assert (g_variant_serialised_check (child));
1581                       return child;
1582 
1583                      )
1584       g_assert_not_reached ();
1585     }
1586 
1587   g_error ("Attempt to access item %"G_GSIZE_FORMAT
1588            " in a container with only %"G_GSIZE_FORMAT" items",
1589            index_, g_variant_serialised_n_children (serialised));
1590 }
1591 
1592 /* < private >
1593  * g_variant_serialiser_serialise:
1594  * @serialised: a #GVariantSerialised, properly set up
1595  * @gvs_filler: the filler function
1596  * @children: an array of child items
1597  * @n_children: the size of @children
1598  *
1599  * Writes data in serialised form.
1600  *
1601  * The type_info field of @serialised must be filled in to type info for
1602  * the type that we are serialising.
1603  *
1604  * The size field of @serialised must be filled in with the value
1605  * returned by a previous call to g_variant_serialiser_needed_size().
1606  *
1607  * The data field of @serialised must be a pointer to a properly-aligned
1608  * memory region large enough to serialise into (ie: at least as big as
1609  * the size field).
1610  *
1611  * This function is only resonsible for serialising the top-level
1612  * container.  @gvs_filler is called on each child of the container in
1613  * order for all of the data of that child to be filled in.
1614  */
1615 void
g_variant_serialiser_serialise(GVariantSerialised serialised,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)1616 g_variant_serialiser_serialise (GVariantSerialised        serialised,
1617                                 GVariantSerialisedFiller  gvs_filler,
1618                                 const gpointer           *children,
1619                                 gsize                     n_children)
1620 {
1621   g_assert (g_variant_serialised_check (serialised));
1622 
1623   DISPATCH_CASES (serialised.type_info,
1624 
1625                   gvs_/**/,/**/_serialise (serialised, gvs_filler,
1626                                            children, n_children);
1627                   return;
1628 
1629                  )
1630   g_assert_not_reached ();
1631 }
1632 
1633 /* < private >
1634  * g_variant_serialiser_needed_size:
1635  * @type_info: the type to serialise for
1636  * @gvs_filler: the filler function
1637  * @children: an array of child items
1638  * @n_children: the size of @children
1639  *
1640  * Determines how much memory would be needed to serialise this value.
1641  *
1642  * This function is only resonsible for performing calculations for the
1643  * top-level container.  @gvs_filler is called on each child of the
1644  * container in order to determine its size.
1645  */
1646 gsize
g_variant_serialiser_needed_size(GVariantTypeInfo * type_info,GVariantSerialisedFiller gvs_filler,const gpointer * children,gsize n_children)1647 g_variant_serialiser_needed_size (GVariantTypeInfo         *type_info,
1648                                   GVariantSerialisedFiller  gvs_filler,
1649                                   const gpointer           *children,
1650                                   gsize                     n_children)
1651 {
1652   DISPATCH_CASES (type_info,
1653 
1654                   return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
1655                                                     children, n_children);
1656 
1657                  )
1658   g_assert_not_reached ();
1659 }
1660 
1661 /* Byteswapping {{{2 */
1662 
1663 /* < private >
1664  * g_variant_serialised_byteswap:
1665  * @value: a #GVariantSerialised
1666  *
1667  * Byte-swap serialised data.  The result of this function is only
1668  * well-defined if the data is in normal form.
1669  */
1670 void
g_variant_serialised_byteswap(GVariantSerialised serialised)1671 g_variant_serialised_byteswap (GVariantSerialised serialised)
1672 {
1673   gsize fixed_size;
1674   guint alignment;
1675 
1676   g_assert (g_variant_serialised_check (serialised));
1677 
1678   if (!serialised.data)
1679     return;
1680 
1681   /* the types we potentially need to byteswap are
1682    * exactly those with alignment requirements.
1683    */
1684   g_variant_type_info_query (serialised.type_info, &alignment, &fixed_size);
1685   if (!alignment)
1686     return;
1687 
1688   /* if fixed size and alignment are equal then we are down
1689    * to the base integer type and we should swap it.  the
1690    * only exception to this is if we have a tuple with a
1691    * single item, and then swapping it will be OK anyway.
1692    */
1693   if (alignment + 1 == fixed_size)
1694     {
1695       switch (fixed_size)
1696       {
1697         case 2:
1698           {
1699             guint16 *ptr = (guint16 *) serialised.data;
1700 
1701             g_assert_cmpint (serialised.size, ==, 2);
1702             *ptr = GUINT16_SWAP_LE_BE (*ptr);
1703           }
1704           return;
1705 
1706         case 4:
1707           {
1708             guint32 *ptr = (guint32 *) serialised.data;
1709 
1710             g_assert_cmpint (serialised.size, ==, 4);
1711             *ptr = GUINT32_SWAP_LE_BE (*ptr);
1712           }
1713           return;
1714 
1715         case 8:
1716           {
1717             guint64 *ptr = (guint64 *) serialised.data;
1718 
1719             g_assert_cmpint (serialised.size, ==, 8);
1720             *ptr = GUINT64_SWAP_LE_BE (*ptr);
1721           }
1722           return;
1723 
1724         default:
1725           g_assert_not_reached ();
1726       }
1727     }
1728 
1729   /* else, we have a container that potentially contains
1730    * some children that need to be byteswapped.
1731    */
1732   else
1733     {
1734       gsize children, i;
1735 
1736       children = g_variant_serialised_n_children (serialised);
1737       for (i = 0; i < children; i++)
1738         {
1739           GVariantSerialised child;
1740 
1741           child = g_variant_serialised_get_child (serialised, i);
1742           g_variant_serialised_byteswap (child);
1743           g_variant_type_info_unref (child.type_info);
1744         }
1745     }
1746 }
1747 
1748 /* Normal form checking {{{2 */
1749 
1750 /* < private >
1751  * g_variant_serialised_is_normal:
1752  * @serialised: a #GVariantSerialised
1753  *
1754  * Determines, recursively if @serialised is in normal form.  There is
1755  * precisely one normal form of serialised data for each possible value.
1756  *
1757  * It is possible that multiple byte sequences form the serialised data
1758  * for a given value if, for example, the padding bytes are filled in
1759  * with something other than zeros, but only one form is the normal
1760  * form.
1761  */
1762 gboolean
g_variant_serialised_is_normal(GVariantSerialised serialised)1763 g_variant_serialised_is_normal (GVariantSerialised serialised)
1764 {
1765   DISPATCH_CASES (serialised.type_info,
1766 
1767                   return gvs_/**/,/**/_is_normal (serialised);
1768 
1769                  )
1770 
1771   if (serialised.data == NULL)
1772     return FALSE;
1773   if (serialised.depth >= G_VARIANT_MAX_RECURSION_DEPTH)
1774     return FALSE;
1775 
1776   /* some hard-coded terminal cases */
1777   switch (g_variant_type_info_get_type_char (serialised.type_info))
1778     {
1779     case 'b': /* boolean */
1780       return serialised.data[0] < 2;
1781 
1782     case 's': /* string */
1783       return g_variant_serialiser_is_string (serialised.data,
1784                                              serialised.size);
1785 
1786     case 'o':
1787       return g_variant_serialiser_is_object_path (serialised.data,
1788                                                   serialised.size);
1789 
1790     case 'g':
1791       return g_variant_serialiser_is_signature (serialised.data,
1792                                                 serialised.size);
1793 
1794     default:
1795       /* all of the other types are fixed-sized numerical types for
1796        * which all possible values are valid (including various NaN
1797        * representations for floating point values).
1798        */
1799       return TRUE;
1800     }
1801 }
1802 
1803 /* Validity-checking functions {{{2
1804  *
1805  * Checks if strings, object paths and signature strings are valid.
1806  */
1807 
1808 /* < private >
1809  * g_variant_serialiser_is_string:
1810  * @data: a possible string
1811  * @size: the size of @data
1812  *
1813  * Ensures that @data is a valid string with a nul terminator at the end
1814  * and no nul bytes embedded.
1815  */
1816 gboolean
g_variant_serialiser_is_string(gconstpointer data,gsize size)1817 g_variant_serialiser_is_string (gconstpointer data,
1818                                 gsize         size)
1819 {
1820   const gchar *expected_end;
1821   const gchar *end;
1822 
1823   /* Strings must end with a nul terminator. */
1824   if (size == 0)
1825     return FALSE;
1826 
1827   expected_end = ((gchar *) data) + size - 1;
1828 
1829   if (*expected_end != '\0')
1830     return FALSE;
1831 
1832   g_utf8_validate_len (data, size, &end);
1833 
1834   return end == expected_end;
1835 }
1836 
1837 /* < private >
1838  * g_variant_serialiser_is_object_path:
1839  * @data: a possible D-Bus object path
1840  * @size: the size of @data
1841  *
1842  * Performs the checks for being a valid string.
1843  *
1844  * Also, ensures that @data is a valid D-Bus object path, as per the D-Bus
1845  * specification.
1846  */
1847 gboolean
g_variant_serialiser_is_object_path(gconstpointer data,gsize size)1848 g_variant_serialiser_is_object_path (gconstpointer data,
1849                                      gsize         size)
1850 {
1851   const gchar *string = data;
1852   gsize i;
1853 
1854   if (!g_variant_serialiser_is_string (data, size))
1855     return FALSE;
1856 
1857   /* The path must begin with an ASCII '/' (integer 47) character */
1858   if (string[0] != '/')
1859     return FALSE;
1860 
1861   for (i = 1; string[i]; i++)
1862     /* Each element must only contain the ASCII characters
1863      * "[A-Z][a-z][0-9]_"
1864      */
1865     if (g_ascii_isalnum (string[i]) || string[i] == '_')
1866       ;
1867 
1868     /* must consist of elements separated by slash characters. */
1869     else if (string[i] == '/')
1870       {
1871         /* No element may be the empty string. */
1872         /* Multiple '/' characters cannot occur in sequence. */
1873         if (string[i - 1] == '/')
1874           return FALSE;
1875       }
1876 
1877     else
1878       return FALSE;
1879 
1880   /* A trailing '/' character is not allowed unless the path is the
1881    * root path (a single '/' character).
1882    */
1883   if (i > 1 && string[i - 1] == '/')
1884     return FALSE;
1885 
1886   return TRUE;
1887 }
1888 
1889 /* < private >
1890  * g_variant_serialiser_is_signature:
1891  * @data: a possible D-Bus signature
1892  * @size: the size of @data
1893  *
1894  * Performs the checks for being a valid string.
1895  *
1896  * Also, ensures that @data is a valid D-Bus type signature, as per the
1897  * D-Bus specification. Note that this means the empty string is valid, as the
1898  * D-Bus specification defines a signature as “zero or more single complete
1899  * types”.
1900  */
1901 gboolean
g_variant_serialiser_is_signature(gconstpointer data,gsize size)1902 g_variant_serialiser_is_signature (gconstpointer data,
1903                                    gsize         size)
1904 {
1905   const gchar *string = data;
1906   gsize first_invalid;
1907 
1908   if (!g_variant_serialiser_is_string (data, size))
1909     return FALSE;
1910 
1911   /* make sure no non-definite characters appear */
1912   first_invalid = strspn (string, "ybnqiuxthdvasog(){}");
1913   if (string[first_invalid])
1914     return FALSE;
1915 
1916   /* make sure each type string is well-formed */
1917   while (*string)
1918     if (!g_variant_type_string_scan (string, NULL, &string))
1919       return FALSE;
1920 
1921   return TRUE;
1922 }
1923 
1924 /* Epilogue {{{1 */
1925 /* vim:set foldmethod=marker: */
1926