LCOV - code coverage report
Current view: top level - glib/glib - gvariant-serialiser.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 555 573 96.9 %
Date: 2024-03-26 05:16:46 Functions: 50 51 98.0 %
Branches: 360 409 88.0 %

           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 (&current_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: */

Generated by: LCOV version 1.14