[glib: 1/2] gvariant: Handle empty serialisations in get_child_value()



commit efe5b701926e01e278ad22afd59a94f2fa7b3fe3
Author: Philip Withnall <withnall endlessm com>
Date:   Tue Aug 20 15:17:40 2019 +0300

    gvariant: Handle empty serialisations in get_child_value()
    
    When g_variant_get_child_value() is called for a child whose
    serialisation is an empty byte string (which is possible), `bytes_data`
    will be non-`NULL`, but `data` may be `NULL`. This results in a negative
    offset being passed to `g_bytes_new_from_bytes()`, and a critical
    warning.
    
    So if `data` is `NULL`, set it to point to `bytes_data` so the offset is
    calculated as zero. The actual value of the offset doesn’t matter, since
    in this situation the size is always zero. An offset of zero is never
    going to cause problems.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>
    Fixes: #1865

 glib/gvariant-core.c  |  6 ++++++
 glib/tests/gvariant.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
---
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
index 123220c1d..9397573a3 100644
--- a/glib/gvariant-core.c
+++ b/glib/gvariant-core.c
@@ -949,6 +949,12 @@ g_variant_get_data_as_bytes (GVariant *value)
   data = value->contents.serialised.data;
   size = value->size;
 
+  if (data == NULL)
+    {
+      g_assert (size == 0);
+      data = bytes_data;
+    }
+
   if (data == bytes_data && size == bytes_size)
     return g_bytes_ref (value->contents.serialised.bytes);
   else
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index ce413bedf..927ae4e12 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -2303,6 +2303,46 @@ test_byteswaps (void)
   g_variant_type_info_assert_no_infos ();
 }
 
+static void
+test_serialiser_children (void)
+{
+  GBytes *data1, *data2;
+  GVariant *child1, *child2;
+  GVariantType *mv_type = g_variant_type_new_maybe (G_VARIANT_TYPE_VARIANT);
+  GVariant *variant, *child;
+
+  g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1865";);
+  g_test_summary ("Test that getting a child variant before and after "
+                  "serialisation of the parent works");
+
+  /* Construct a variable sized array containing a child which serialises to a
+   * zero-length bytestring. */
+  child = g_variant_new_maybe (G_VARIANT_TYPE_VARIANT, NULL);
+  variant = g_variant_new_array (mv_type, &child, 1);
+
+  /* Get the child before serialising. */
+  child1 = g_variant_get_child_value (variant, 0);
+  data1 = g_variant_get_data_as_bytes (child1);
+
+  /* Serialise the parent variant. */
+  g_variant_get_data (variant);
+
+  /* Get the child again after serialising — this uses a different code path. */
+  child2 = g_variant_get_child_value (variant, 0);
+  data2 = g_variant_get_data_as_bytes (child2);
+
+  /* Check things are equal. */
+  g_assert_cmpvariant (child1, child2);
+  g_assert_true (g_bytes_equal (data1, data2));
+
+  g_variant_unref (child2);
+  g_variant_unref (child1);
+  g_variant_unref (variant);
+  g_bytes_unref (data2);
+  g_bytes_unref (data1);
+  g_variant_type_free (mv_type);
+}
+
 static void
 test_fuzz (gdouble *fuzziness)
 {
@@ -5075,6 +5115,7 @@ main (int argc, char **argv)
   guint i;
 
   g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("");
 
   g_test_add_func ("/gvariant/type", test_gvarianttype);
   g_test_add_func ("/gvariant/type/string-scan/recursion/tuple",
@@ -5088,6 +5129,7 @@ main (int argc, char **argv)
   g_test_add_func ("/gvariant/serialiser/variant", test_variants);
   g_test_add_func ("/gvariant/serialiser/strings", test_strings);
   g_test_add_func ("/gvariant/serialiser/byteswap", test_byteswaps);
+  g_test_add_func ("/gvariant/serialiser/children", test_serialiser_children);
 
   for (i = 1; i <= 20; i += 4)
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]