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