Fix getauxval error at qemu
[platform/upstream/glib.git] / glib / gvarianttypeinfo.c
1 /*
2  * Copyright © 2008 Ryan Lortie
3  * Copyright © 2010 Codethink Limited
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author: Ryan Lortie <desrt@desrt.ca>
21  */
22
23 #include "config.h"
24
25 #include "gvarianttypeinfo.h"
26
27 #include <glib/gtestutils.h>
28 #include <glib/gthread.h>
29 #include <glib/gslice.h>
30 #include <glib/ghash.h>
31 #include <glib/grefcount.h>
32
33 #include "glib_trace.h"
34
35 /* < private >
36  * GVariantTypeInfo:
37  *
38  * This structure contains the necessary information to facilitate the
39  * serialization and fast deserialization of a given type of GVariant
40  * value.  A GVariant instance holds a pointer to one of these
41  * structures to provide for efficient operation.
42  *
43  * The GVariantTypeInfo structures for all of the base types, plus the
44  * "variant" type are stored in a read-only static array.
45  *
46  * For container types, a hash table and reference counting is used to
47  * ensure that only one of these structures exists for any given type.
48  * In general, a container GVariantTypeInfo will exist for a given type
49  * only if one or more GVariant instances of that type exist or if
50  * another GVariantTypeInfo has that type as a subtype.  For example, if
51  * a process contains a single GVariant instance with type "(asv)", then
52  * container GVariantTypeInfo structures will exist for "(asv)" and
53  * for "as" (note that "s" and "v" always exist in the static array).
54  *
55  * The trickiest part of GVariantTypeInfo (and in fact, the major reason
56  * for its existence) is the storage of somewhat magical constants that
57  * allow for O(1) lookups of items in tuples.  This is described below.
58  *
59  * 'container_class' is set to 'a' or 'r' if the GVariantTypeInfo is
60  * contained inside of an ArrayInfo or TupleInfo, respectively.  This
61  * allows the storage of the necessary additional information.
62  *
63  * 'fixed_size' is set to the fixed size of the type, if applicable, or
64  * 0 otherwise (since no type has a fixed size of 0).
65  *
66  * 'alignment' is set to one less than the alignment requirement for
67  * this type.  This makes many operations much more convenient.
68  */
69 struct _GVariantTypeInfo
70 {
71   gsize fixed_size;
72   guchar alignment;
73   guchar container_class;
74 };
75
76 /* Container types are reference counted.  They also need to have their
77  * type string stored explicitly since it is not merely a single letter.
78  */
79 typedef struct
80 {
81   GVariantTypeInfo info;
82
83   gchar *type_string;
84   gatomicrefcount ref_count;
85 } ContainerInfo;
86
87 /* For 'array' and 'maybe' types, we store some extra information on the
88  * end of the GVariantTypeInfo struct -- the element type (ie: "s" for
89  * "as").  The container GVariantTypeInfo structure holds a reference to
90  * the element typeinfo.
91  */
92 typedef struct
93 {
94   ContainerInfo container;
95
96   GVariantTypeInfo *element;
97 } ArrayInfo;
98
99 /* For 'tuple' and 'dict entry' types, we store extra information for
100  * each member -- its type and how to find it inside the serialized data
101  * in O(1) time using 4 variables -- 'i', 'a', 'b', and 'c'.  See the
102  * comment on GVariantMemberInfo in gvarianttypeinfo.h.
103  */
104 typedef struct
105 {
106   ContainerInfo container;
107
108   GVariantMemberInfo *members;
109   gsize n_members;
110 } TupleInfo;
111
112
113 /* Hard-code the base types in a constant array */
114 static const GVariantTypeInfo g_variant_type_info_basic_table[24] = {
115 #define fixed_aligned(x)  x, x - 1, 0
116 #define not_a_type        0,     0, 0
117 #define unaligned         0,     0, 0
118 #define aligned(x)        0, x - 1, 0
119   /* 'b' */ { fixed_aligned(1) },   /* boolean */
120   /* 'c' */ { not_a_type },
121   /* 'd' */ { fixed_aligned(8) },   /* double */
122   /* 'e' */ { not_a_type },
123   /* 'f' */ { not_a_type },
124   /* 'g' */ { unaligned        },   /* signature string */
125   /* 'h' */ { fixed_aligned(4) },   /* file handle (int32) */
126   /* 'i' */ { fixed_aligned(4) },   /* int32 */
127   /* 'j' */ { not_a_type },
128   /* 'k' */ { not_a_type },
129   /* 'l' */ { not_a_type },
130   /* 'm' */ { not_a_type },
131   /* 'n' */ { fixed_aligned(2) },   /* int16 */
132   /* 'o' */ { unaligned        },   /* object path string */
133   /* 'p' */ { not_a_type },
134   /* 'q' */ { fixed_aligned(2) },   /* uint16 */
135   /* 'r' */ { not_a_type },
136   /* 's' */ { unaligned        },   /* string */
137   /* 't' */ { fixed_aligned(8) },   /* uint64 */
138   /* 'u' */ { fixed_aligned(4) },   /* uint32 */
139   /* 'v' */ { aligned(8)       },   /* variant */
140   /* 'w' */ { not_a_type },
141   /* 'x' */ { fixed_aligned(8) },   /* int64 */
142   /* 'y' */ { fixed_aligned(1) },   /* byte */
143 #undef fixed_aligned
144 #undef not_a_type
145 #undef unaligned
146 #undef aligned
147 };
148
149 /* We need to have type strings to return for the base types.  We store
150  * those in another array.  Since all base type strings are single
151  * characters this is easy.  By not storing pointers to strings into the
152  * GVariantTypeInfo itself, we save a bunch of relocations.
153  */
154 static const char g_variant_type_info_basic_chars[24][2] = {
155   "b", " ", "d", " ", " ", "g", "h", "i", " ", " ", " ", " ",
156   "n", "o", " ", "q", " ", "s", "t", "u", "v", " ", "x", "y"
157 };
158
159 /* sanity checks to make debugging easier */
160 static void
161 g_variant_type_info_check (const GVariantTypeInfo *info,
162                            char                    container_class)
163 {
164 #ifndef G_DISABLE_ASSERT
165   g_assert (!container_class || info->container_class == container_class);
166
167   /* alignment can only be one of these */
168   g_assert (info->alignment == 0 || info->alignment == 1 ||
169             info->alignment == 3 || info->alignment == 7);
170
171   if (info->container_class)
172     {
173       ContainerInfo *container = (ContainerInfo *) info;
174
175       /* extra checks for containers */
176       g_assert (!g_atomic_ref_count_compare (&container->ref_count, 0));
177       g_assert (container->type_string != NULL);
178     }
179   else
180     {
181       gint index;
182
183       /* if not a container, then ensure that it is a valid member of
184        * the basic types table
185        */
186       index = info - g_variant_type_info_basic_table;
187
188       g_assert (G_N_ELEMENTS (g_variant_type_info_basic_table) == 24);
189       g_assert (G_N_ELEMENTS (g_variant_type_info_basic_chars) == 24);
190       g_assert (0 <= index && index < 24);
191       g_assert (g_variant_type_info_basic_chars[index][0] != ' ');
192     }
193 #endif  /* !G_DISABLE_ASSERT */
194 }
195
196 /* < private >
197  * g_variant_type_info_get_type_string:
198  * @info: a #GVariantTypeInfo
199  *
200  * Gets the type string for @info.  The string is nul-terminated.
201  */
202 const gchar *
203 g_variant_type_info_get_type_string (GVariantTypeInfo *info)
204 {
205   g_variant_type_info_check (info, 0);
206
207   if (info->container_class)
208     {
209       ContainerInfo *container = (ContainerInfo *) info;
210
211       /* containers have their type string stored inside them */
212       return container->type_string;
213     }
214   else
215     {
216       gint index;
217
218       /* look up the type string in the base type array.  the call to
219        * g_variant_type_info_check() above already ensured validity.
220        */
221       index = info - g_variant_type_info_basic_table;
222
223       return g_variant_type_info_basic_chars[index];
224     }
225 }
226
227 /* < private >
228  * g_variant_type_info_query:
229  * @info: a #GVariantTypeInfo
230  * @alignment: (out) (optional): the location to store the alignment, or %NULL
231  * @fixed_size: (out) (optional): the location to store the fixed size, or %NULL
232  *
233  * Queries @info to determine the alignment requirements and fixed size
234  * (if any) of the type.
235  *
236  * @fixed_size, if non-%NULL is set to the fixed size of the type, or 0
237  * to indicate that the type is a variable-sized type.  No type has a
238  * fixed size of 0.
239  *
240  * @alignment, if non-%NULL, is set to one less than the required
241  * alignment of the type.  For example, for a 32bit integer, @alignment
242  * would be set to 3.  This allows you to round an integer up to the
243  * proper alignment by performing the following efficient calculation:
244  *
245  *   offset += ((-offset) & alignment);
246  */
247 void
248 g_variant_type_info_query (GVariantTypeInfo *info,
249                            guint            *alignment,
250                            gsize            *fixed_size)
251 {
252   if (alignment)
253     *alignment = info->alignment;
254
255   if (fixed_size)
256     *fixed_size = info->fixed_size;
257 }
258
259 /* < private >
260  * g_variant_type_info_query_depth:
261  * @info: a #GVariantTypeInfo
262  *
263  * Queries @info to determine the depth of the type.
264  *
265  * See g_variant_type_string_get_depth_() for more details.
266  *
267  * Returns: depth of @info
268  * Since: 2.60
269  */
270 gsize
271 g_variant_type_info_query_depth (GVariantTypeInfo *info)
272 {
273   g_variant_type_info_check (info, 0);
274
275   if (info->container_class)
276     {
277       ContainerInfo *container = (ContainerInfo *) info;
278       return g_variant_type_string_get_depth_ (container->type_string);
279     }
280
281   return 1;
282 }
283
284 /* == array == */
285 #define GV_ARRAY_INFO_CLASS 'a'
286 static ArrayInfo *
287 GV_ARRAY_INFO (GVariantTypeInfo *info)
288 {
289   g_variant_type_info_check (info, GV_ARRAY_INFO_CLASS);
290
291   return (ArrayInfo *) info;
292 }
293
294 static void
295 array_info_free (GVariantTypeInfo *info)
296 {
297   ArrayInfo *array_info;
298
299   g_assert (info->container_class == GV_ARRAY_INFO_CLASS);
300   array_info = (ArrayInfo *) info;
301
302   g_variant_type_info_unref (array_info->element);
303   g_slice_free (ArrayInfo, array_info);
304 }
305
306 static ContainerInfo *
307 array_info_new (const GVariantType *type)
308 {
309   ArrayInfo *info;
310
311   info = g_slice_new (ArrayInfo);
312   info->container.info.container_class = GV_ARRAY_INFO_CLASS;
313
314   info->element = g_variant_type_info_get (g_variant_type_element (type));
315   info->container.info.alignment = info->element->alignment;
316   info->container.info.fixed_size = 0;
317
318   return (ContainerInfo *) info;
319 }
320
321 /* < private >
322  * g_variant_type_info_element:
323  * @info: a #GVariantTypeInfo for an array or maybe type
324  *
325  * Returns the element type for the array or maybe type.  A reference is
326  * not added, so the caller must add their own.
327  */
328 GVariantTypeInfo *
329 g_variant_type_info_element (GVariantTypeInfo *info)
330 {
331   return GV_ARRAY_INFO (info)->element;
332 }
333
334 /* < private >
335  * g_variant_type_query_element:
336  * @info: a #GVariantTypeInfo for an array or maybe type
337  * @alignment: (out) (optional): the location to store the alignment, or %NULL
338  * @fixed_size: (out) (optional): the location to store the fixed size, or %NULL
339  *
340  * Returns the alignment requires and fixed size (if any) for the
341  * element type of the array.  This call is a convenience wrapper around
342  * g_variant_type_info_element() and g_variant_type_info_query().
343  */
344 void
345 g_variant_type_info_query_element (GVariantTypeInfo *info,
346                                    guint            *alignment,
347                                    gsize            *fixed_size)
348 {
349   g_variant_type_info_query (GV_ARRAY_INFO (info)->element,
350                              alignment, fixed_size);
351 }
352
353 /* == tuple == */
354 #define GV_TUPLE_INFO_CLASS 'r'
355 static TupleInfo *
356 GV_TUPLE_INFO (GVariantTypeInfo *info)
357 {
358   g_variant_type_info_check (info, GV_TUPLE_INFO_CLASS);
359
360   return (TupleInfo *) info;
361 }
362
363 static void
364 tuple_info_free (GVariantTypeInfo *info)
365 {
366   TupleInfo *tuple_info;
367   gsize i;
368
369   g_assert (info->container_class == GV_TUPLE_INFO_CLASS);
370   tuple_info = (TupleInfo *) info;
371
372   for (i = 0; i < tuple_info->n_members; i++)
373     g_variant_type_info_unref (tuple_info->members[i].type_info);
374
375   g_slice_free1 (sizeof (GVariantMemberInfo) * tuple_info->n_members,
376                  tuple_info->members);
377   g_slice_free (TupleInfo, tuple_info);
378 }
379
380 static void
381 tuple_allocate_members (const GVariantType  *type,
382                         GVariantMemberInfo **members,
383                         gsize               *n_members)
384 {
385   const GVariantType *item_type;
386   gsize i = 0;
387
388   *n_members = g_variant_type_n_items (type);
389   *members = g_slice_alloc (sizeof (GVariantMemberInfo) * *n_members);
390
391   item_type = g_variant_type_first (type);
392   while (item_type)
393     {
394       GVariantMemberInfo *member = &(*members)[i++];
395
396       member->type_info = g_variant_type_info_get (item_type);
397       item_type = g_variant_type_next (item_type);
398
399       if (member->type_info->fixed_size)
400         member->ending_type = G_VARIANT_MEMBER_ENDING_FIXED;
401       else if (item_type == NULL)
402         member->ending_type = G_VARIANT_MEMBER_ENDING_LAST;
403       else
404         member->ending_type = G_VARIANT_MEMBER_ENDING_OFFSET;
405     }
406
407   g_assert (i == *n_members);
408 }
409
410 /* this is g_variant_type_info_query for a given member of the tuple.
411  * before the access is done, it is ensured that the item is within
412  * range and %FALSE is returned if not.
413  */
414 static gboolean
415 tuple_get_item (TupleInfo          *info,
416                 GVariantMemberInfo *item,
417                 gsize              *d,
418                 gsize              *e)
419 {
420   if (&info->members[info->n_members] == item)
421     return FALSE;
422
423   *d = item->type_info->alignment;
424   *e = item->type_info->fixed_size;
425   return TRUE;
426 }
427
428 /* Read the documentation for #GVariantMemberInfo in gvarianttype.h
429  * before attempting to understand this.
430  *
431  * This function adds one set of "magic constant" values (for one item
432  * in the tuple) to the table.
433  *
434  * The algorithm in tuple_generate_table() calculates values of 'a', 'b'
435  * and 'c' for each item, such that the procedure for finding the item
436  * is to start at the end of the previous variable-sized item, add 'a',
437  * then round up to the nearest multiple of 'b', then then add 'c'.
438  * Note that 'b' is stored in the usual "one less than" form.  ie:
439  *
440  *   start = ROUND_UP(prev_end + a, (b + 1)) + c;
441  *
442  * We tweak these values a little to allow for a slightly easier
443  * computation and more compact storage.
444  */
445 static void
446 tuple_table_append (GVariantMemberInfo **items,
447                     gsize                i,
448                     gsize                a,
449                     gsize                b,
450                     gsize                c)
451 {
452   GVariantMemberInfo *item = (*items)++;
453
454   /* We can shift multiples of the alignment size from 'c' into 'a'.
455    * As long as we're shifting whole multiples, it won't affect the
456    * result.  This means that we can take the "aligned" portion off of
457    * 'c' and add it into 'a'.
458    *
459    *  Imagine (for sake of clarity) that ROUND_10 rounds up to the
460    *  nearest 10.  It is clear that:
461    *
462    *   ROUND_10(a) + c == ROUND_10(a + 10*(c / 10)) + (c % 10)
463    *
464    * ie: remove the 10s portion of 'c' and add it onto 'a'.
465    *
466    * To put some numbers on it, imagine we start with a = 34 and c = 27:
467    *
468    *  ROUND_10(34) + 27 = 40 + 27 = 67
469    *
470    * but also, we can split 27 up into 20 and 7 and do this:
471    *
472    *  ROUND_10(34 + 20) + 7 = ROUND_10(54) + 7 = 60 + 7 = 67
473    *                ^^    ^
474    * without affecting the result.  We do that here.
475    *
476    * This reduction in the size of 'c' means that we can store it in a
477    * gchar instead of a gsize.  Due to how the structure is packed, this
478    * ends up saving us 'two pointer sizes' per item in each tuple when
479    * allocating using GSlice.
480    */
481   a += ~b & c;    /* take the "aligned" part of 'c' and add to 'a' */
482   c &= b;         /* chop 'c' to contain only the unaligned part */
483
484
485   /* Finally, we made one last adjustment.  Recall:
486    *
487    *   start = ROUND_UP(prev_end + a, (b + 1)) + c;
488    *
489    * Forgetting the '+ c' for the moment:
490    *
491    *   ROUND_UP(prev_end + a, (b + 1));
492    *
493    * we can do a "round up" operation by adding 1 less than the amount
494    * to round up to, then rounding down.  ie:
495    *
496    *   #define ROUND_UP(x, y)    ROUND_DOWN(x + (y-1), y)
497    *
498    * Of course, for rounding down to a power of two, we can just mask
499    * out the appropriate number of low order bits:
500    *
501    *   #define ROUND_DOWN(x, y)  (x & ~(y - 1))
502    *
503    * Which gives us
504    *
505    *   #define ROUND_UP(x, y)    (x + (y - 1) & ~(y - 1))
506    *
507    * but recall that our alignment value 'b' is already "one less".
508    * This means that to round 'prev_end + a' up to 'b' we can just do:
509    *
510    *   ((prev_end + a) + b) & ~b
511    *
512    * Associativity, and putting the 'c' back on:
513    *
514    *   (prev_end + (a + b)) & ~b + c
515    *
516    * Now, since (a + b) is constant, we can just add 'b' to 'a' now and
517    * store that as the number to add to prev_end.  Then we use ~b as the
518    * number to take a bitwise 'and' with.  Finally, 'c' is added on.
519    *
520    * Note, however, that all the low order bits of the 'aligned' value
521    * are masked out and that all of the high order bits of 'c' have been
522    * "moved" to 'a' (in the previous step).  This means that there are
523    * no overlapping bits in the addition -- so we can do a bitwise 'or'
524    * equivalently.
525    *
526    * This means that we can now compute the start address of a given
527    * item in the tuple using the algorithm given in the documentation
528    * for #GVariantMemberInfo:
529    *
530    *   item_start = ((prev_end + a) & b) | c;
531    */
532
533   item->i = i;
534   item->a = a + b;
535   item->b = ~b;
536   item->c = c;
537 }
538
539 static gsize
540 tuple_align (gsize offset,
541              guint alignment)
542 {
543   return offset + ((-offset) & alignment);
544 }
545
546 /* This function is the heart of the algorithm for calculating 'i', 'a',
547  * 'b' and 'c' for each item in the tuple.
548  *
549  * Imagine we want to find the start of the "i" in the type "(su(qx)ni)".
550  * That's a string followed by a uint32, then a tuple containing a
551  * uint16 and an int64, then an int16, then our "i".  In order to get to
552  * our "i" we:
553  *
554  * Start at the end of the string, align to 4 (for the uint32), add 4.
555  * Align to 8, add 16 (for the tuple).  Align to 2, add 2 (for the
556  * int16).  Then we're there.  It turns out that, given 3 simple rules,
557  * we can flatten this iteration into one addition, one alignment, then
558  * one more addition.
559  *
560  * The loop below plays through each item in the tuple, querying its
561  * alignment and fixed_size into 'd' and 'e', respectively.  At all
562  * times the variables 'a', 'b', and 'c' are maintained such that in
563  * order to get to the current point, you add 'a', align to 'b' then add
564  * 'c'.  'b' is kept in "one less than" form.  For each item, the proper
565  * alignment is applied to find the values of 'a', 'b' and 'c' to get to
566  * the start of that item.  Those values are recorded into the table.
567  * The fixed size of the item (if applicable) is then added on.
568  *
569  * These 3 rules are how 'a', 'b' and 'c' are modified for alignment and
570  * addition of fixed size.  They have been proven correct but are
571  * presented here, without proof:
572  *
573  *  1) in order to "align to 'd'" where 'd' is less than or equal to the
574  *     largest level of alignment seen so far ('b'), you align 'c' to
575  *     'd'.
576  *  2) in order to "align to 'd'" where 'd' is greater than the largest
577  *     level of alignment seen so far, you add 'c' aligned to 'b' to the
578  *     value of 'a', set 'b' to 'd' (ie: increase the 'largest alignment
579  *     seen') and reset 'c' to 0.
580  *  3) in order to "add 'e'", just add 'e' to 'c'.
581  */
582 static void
583 tuple_generate_table (TupleInfo *info)
584 {
585   GVariantMemberInfo *items = info->members;
586   gsize i = -1, a = 0, b = 0, c = 0, d, e;
587
588   /* iterate over each item in the tuple.
589    *   'd' will be the alignment of the item (in one-less form)
590    *   'e' will be the fixed size (or 0 for variable-size items)
591    */
592   while (tuple_get_item (info, items, &d, &e))
593     {
594       /* align to 'd' */
595       if (d <= b)
596         c = tuple_align (c, d);                   /* rule 1 */
597       else
598         a += tuple_align (c, b), b = d, c = 0;    /* rule 2 */
599
600       /* the start of the item is at this point (ie: right after we
601        * have aligned for it).  store this information in the table.
602        */
603       tuple_table_append (&items, i, a, b, c);
604
605       /* "move past" the item by adding in its size. */
606       if (e == 0)
607         /* variable size:
608          *
609          * we'll have an offset stored to mark the end of this item, so
610          * just bump the offset index to give us a new starting point
611          * and reset all the counters.
612          */
613         i++, a = b = c = 0;
614       else
615         /* fixed size */
616         c += e;                                   /* rule 3 */
617     }
618 }
619
620 static void
621 tuple_set_base_info (TupleInfo *info)
622 {
623   GVariantTypeInfo *base = &info->container.info;
624
625   if (info->n_members > 0)
626     {
627       GVariantMemberInfo *m;
628
629       /* the alignment requirement of the tuple is the alignment
630        * requirement of its largest item.
631        */
632       base->alignment = 0;
633       for (m = info->members; m < &info->members[info->n_members]; m++)
634         /* can find the max of a list of "one less than" powers of two
635          * by 'or'ing them
636          */
637         base->alignment |= m->type_info->alignment;
638
639       m--; /* take 'm' back to the last item */
640
641       /* the structure only has a fixed size if no variable-size
642        * offsets are stored and the last item is fixed-sized too (since
643        * an offset is never stored for the last item).
644        */
645       if (m->i == (gsize) -1 && m->type_info->fixed_size)
646         /* in that case, the fixed size can be found by finding the
647          * start of the last item (in the usual way) and adding its
648          * fixed size.
649          *
650          * if a tuple has a fixed size then it is always a multiple of
651          * the alignment requirement (to make packing into arrays
652          * easier) so we round up to that here.
653          */
654         base->fixed_size =
655           tuple_align (((m->a & m->b) | m->c) + m->type_info->fixed_size,
656                        base->alignment);
657       else
658         /* else, the tuple is not fixed size */
659         base->fixed_size = 0;
660     }
661   else
662     {
663       /* the empty tuple: '()'.
664        *
665        * has a size of 1 and a no alignment requirement.
666        *
667        * It has a size of 1 (not 0) for two practical reasons:
668        *
669        *  1) So we can determine how many of them are in an array
670        *     without dividing by zero or without other tricks.
671        *
672        *  2) Even if we had some trick to know the number of items in
673        *     the array (as GVariant did at one time) this would open a
674        *     potential denial of service attack: an attacker could send
675        *     you an extremely small array (in terms of number of bytes)
676        *     containing trillions of zero-sized items.  If you iterated
677        *     over this array you would effectively infinite-loop your
678        *     program.  By forcing a size of at least one, we bound the
679        *     amount of computation done in response to a message to a
680        *     reasonable function of the size of that message.
681        */
682       base->alignment = 0;
683       base->fixed_size = 1;
684     }
685 }
686
687 static ContainerInfo *
688 tuple_info_new (const GVariantType *type)
689 {
690   TupleInfo *info;
691
692   info = g_slice_new (TupleInfo);
693   info->container.info.container_class = GV_TUPLE_INFO_CLASS;
694
695   tuple_allocate_members (type, &info->members, &info->n_members);
696   tuple_generate_table (info);
697   tuple_set_base_info (info);
698
699   return (ContainerInfo *) info;
700 }
701
702 /* < private >
703  * g_variant_type_info_n_members:
704  * @info: a #GVariantTypeInfo for a tuple or dictionary entry type
705  *
706  * Returns the number of members in a tuple or dictionary entry type.
707  * For a dictionary entry this will always be 2.
708  */
709 gsize
710 g_variant_type_info_n_members (GVariantTypeInfo *info)
711 {
712   return GV_TUPLE_INFO (info)->n_members;
713 }
714
715 /* < private >
716  * g_variant_type_info_member_info:
717  * @info: a #GVariantTypeInfo for a tuple or dictionary entry type
718  * @index: the member to fetch information for
719  *
720  * Returns the #GVariantMemberInfo for a given member.  See
721  * documentation for that structure for why you would want this
722  * information.
723  *
724  * @index must refer to a valid child (ie: strictly less than
725  * g_variant_type_info_n_members() returns).
726  */
727 const GVariantMemberInfo *
728 g_variant_type_info_member_info (GVariantTypeInfo *info,
729                                  gsize             index)
730 {
731   TupleInfo *tuple_info = GV_TUPLE_INFO (info);
732
733   if (index < tuple_info->n_members)
734     return &tuple_info->members[index];
735
736   return NULL;
737 }
738
739 /* == new/ref/unref == */
740 static GRecMutex g_variant_type_info_lock;
741 static GHashTable *g_variant_type_info_table;
742
743 /* < private >
744  * g_variant_type_info_get:
745  * @type: a #GVariantType
746  *
747  * Returns a reference to a #GVariantTypeInfo for @type.
748  *
749  * If an info structure already exists for this type, a new reference is
750  * returned.  If not, the required calculations are performed and a new
751  * info structure is returned.
752  *
753  * It is appropriate to call g_variant_type_info_unref() on the return
754  * value.
755  */
756 GVariantTypeInfo *
757 g_variant_type_info_get (const GVariantType *type)
758 {
759   char type_char;
760
761   type_char = g_variant_type_peek_string (type)[0];
762
763   if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE ||
764       type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY ||
765       type_char == G_VARIANT_TYPE_INFO_CHAR_TUPLE ||
766       type_char == G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY)
767     {
768       GVariantTypeInfo *info;
769       gchar *type_string;
770
771       type_string = g_variant_type_dup_string (type);
772
773       g_rec_mutex_lock (&g_variant_type_info_lock);
774
775       if (g_variant_type_info_table == NULL)
776         g_variant_type_info_table = g_hash_table_new (g_str_hash,
777                                                       g_str_equal);
778       info = g_hash_table_lookup (g_variant_type_info_table, type_string);
779
780       if (info == NULL)
781         {
782           ContainerInfo *container;
783
784           if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE ||
785               type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY)
786             {
787               container = array_info_new (type);
788             }
789           else /* tuple or dict entry */
790             {
791               container = tuple_info_new (type);
792             }
793
794           info = (GVariantTypeInfo *) container;
795           container->type_string = type_string;
796           g_atomic_ref_count_init (&container->ref_count);
797
798           TRACE(GLIB_VARIANT_TYPE_INFO_NEW(info, container->type_string));
799
800           g_hash_table_insert (g_variant_type_info_table, type_string, info);
801           type_string = NULL;
802         }
803       else
804         g_variant_type_info_ref (info);
805
806       g_rec_mutex_unlock (&g_variant_type_info_lock);
807       g_variant_type_info_check (info, 0);
808       g_free (type_string);
809
810       return info;
811     }
812   else
813     {
814       const GVariantTypeInfo *info;
815       int index;
816
817       index = type_char - 'b';
818       g_assert (G_N_ELEMENTS (g_variant_type_info_basic_table) == 24);
819       g_assert_cmpint (0, <=, index);
820       g_assert_cmpint (index, <, 24);
821
822       info = g_variant_type_info_basic_table + index;
823       g_variant_type_info_check (info, 0);
824
825       TRACE(GLIB_VARIANT_TYPE_INFO_NEW(info, g_variant_type_info_basic_chars[index]));
826
827       return (GVariantTypeInfo *) info;
828     }
829 }
830
831 /* < private >
832  * g_variant_type_info_ref:
833  * @info: a #GVariantTypeInfo
834  *
835  * Adds a reference to @info.
836  */
837 GVariantTypeInfo *
838 g_variant_type_info_ref (GVariantTypeInfo *info)
839 {
840   g_variant_type_info_check (info, 0);
841
842   if (info->container_class)
843     {
844       ContainerInfo *container = (ContainerInfo *) info;
845
846       g_atomic_ref_count_inc (&container->ref_count);
847     }
848
849   return info;
850 }
851
852 /* < private >
853  * g_variant_type_info_unref:
854  * @info: a #GVariantTypeInfo
855  *
856  * Releases a reference held on @info.  This may result in @info being
857  * freed.
858  */
859 void
860 g_variant_type_info_unref (GVariantTypeInfo *info)
861 {
862   g_variant_type_info_check (info, 0);
863
864   if (info->container_class)
865     {
866       ContainerInfo *container = (ContainerInfo *) info;
867
868       g_rec_mutex_lock (&g_variant_type_info_lock);
869       if (g_atomic_ref_count_dec (&container->ref_count))
870         {
871
872           TRACE(GLIB_VARIANT_TYPE_INFO_FREE(info));
873
874           g_hash_table_remove (g_variant_type_info_table,
875                                container->type_string);
876           if (g_hash_table_size (g_variant_type_info_table) == 0)
877             {
878               g_hash_table_unref (g_variant_type_info_table);
879               g_variant_type_info_table = NULL;
880             }
881           g_rec_mutex_unlock (&g_variant_type_info_lock);
882
883           g_free (container->type_string);
884
885           if (info->container_class == GV_ARRAY_INFO_CLASS)
886             array_info_free (info);
887
888           else if (info->container_class == GV_TUPLE_INFO_CLASS)
889             tuple_info_free (info);
890
891           else
892             g_assert_not_reached ();
893         }
894       else
895         g_rec_mutex_unlock (&g_variant_type_info_lock);
896     }
897 }
898
899 void
900 g_variant_type_info_assert_no_infos (void)
901 {
902   g_assert (g_variant_type_info_table == NULL);
903 }