mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-10-02 11:56:38 +02:00
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:
@@ -944,6 +944,10 @@ gvs_variable_sized_array_is_normal (GVariantSerialised value)
|
||||
* for the tuple. See the notes in gvarianttypeinfo.h.
|
||||
*/
|
||||
|
||||
/* Note: This doesn’t guarantee that @out_member_end >= @out_member_start; that
|
||||
* condition may not hold true for invalid serialised variants. The caller is
|
||||
* responsible for checking the returned values and handling invalid ones
|
||||
* appropriately. */
|
||||
static void
|
||||
gvs_tuple_get_member_bounds (GVariantSerialised value,
|
||||
gsize index_,
|
||||
@@ -1030,6 +1034,42 @@ gvs_tuple_get_child (GVariantSerialised value,
|
||||
return child;
|
||||
}
|
||||
|
||||
/* If the requested @index_ is beyond the set of indices whose framing offsets
|
||||
* have been checked, check the remaining offsets to see whether they’re
|
||||
* normal (in order, no overlapping tuple elements).
|
||||
*
|
||||
* Unlike the checks in gvs_variable_sized_array_get_child(), we have to check
|
||||
* all the tuple *elements* here, not just all the framing offsets, since
|
||||
* tuples contain a mix of elements which use framing offsets and ones which
|
||||
* don’t. None of them are allowed to overlap. */
|
||||
if (index_ > value.ordered_offsets_up_to)
|
||||
{
|
||||
gsize i, prev_i_end = 0;
|
||||
|
||||
if (value.ordered_offsets_up_to > 0)
|
||||
gvs_tuple_get_member_bounds (value, value.ordered_offsets_up_to - 1, offset_size, NULL, &prev_i_end);
|
||||
|
||||
for (i = value.ordered_offsets_up_to; i <= index_; i++)
|
||||
{
|
||||
gsize i_start, i_end;
|
||||
|
||||
gvs_tuple_get_member_bounds (value, i, offset_size, &i_start, &i_end);
|
||||
|
||||
if (i_start > i_end || i_start < prev_i_end || i_end > value.size)
|
||||
break;
|
||||
|
||||
prev_i_end = i_end;
|
||||
}
|
||||
|
||||
value.ordered_offsets_up_to = i - 1;
|
||||
}
|
||||
|
||||
if (index_ > value.ordered_offsets_up_to)
|
||||
{
|
||||
/* Offsets are invalid somewhere, so return an empty child. */
|
||||
return child;
|
||||
}
|
||||
|
||||
if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
|
||||
{
|
||||
if (offset_size * (member_info->i + 2) > value.size)
|
||||
|
Reference in New Issue
Block a user