gvariant: Don’t allow child elements of a tuple to overlap each other

This is similar to the earlier commit which prevents child elements of a
variable-sized array from overlapping each other, but this time for
tuples. It is based heavily on ideas by William Manley.

Tuples are slightly different from variable-sized arrays in that they
contain a mixture of fixed and variable sized elements. All but one of
the variable sized elements have an entry in the frame offsets table.
This means that if we were to just check the ordering of the frame
offsets table, the variable sized elements could still overlap
interleaving fixed sized elements, which would be bad.

Therefore we have to check the elements rather than the frame offsets.

The logic of checking the elements up to the index currently being
requested, and caching the result in `ordered_offsets_up_to`, means that
the algorithmic cost implications are the same for this commit as for
variable-sized arrays: an O(N) cost for these checks is amortised out
over N accesses to O(1) per access.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #2121
This commit is contained in:
Philip Withnall
2022-01-07 16:42:14 +00:00
parent 73d0aa81c2
commit 7cf6f5b691
5 changed files with 232 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
/*
* Copyright © 2007, 2008 Ryan Lortie
* Copyright © 2010 Codethink Limited
* Copyright © 2022 Endless OS Foundation, LLC
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
@@ -181,7 +182,7 @@ struct _GVariant
* offsets themselves.
*
* This field is only relevant for arrays of non
* fixed width types.
* fixed width types and for tuples.
*
* .tree: Only valid when the instance is in tree form.
*
@@ -1141,6 +1142,9 @@ g_variant_get_child_value (GVariant *value,
*/
s_child = g_variant_serialised_get_child (serialised, index_);
/* Update the cached ordered_offsets_up_to, since @serialised will be thrown away when this function exits */
value->contents.serialised.ordered_offsets_up_to = MAX (value->contents.serialised.ordered_offsets_up_to, serialised.ordered_offsets_up_to);
/* Check whether this would cause nesting too deep. If so, return a fake
* child. The only situation we expect this to happen in is with a variant,
* as all other deeply-nested types have a static type, and hence should