From 51b822787ec55c1f03af359160ef48a2ac3a59db Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Mon, 27 Apr 2020 16:41:14 -0700 Subject: [PATCH] gvariant-core: Add a note about memory safety of children When g_variant_get_child() is called on a variant which has not been serialized, it serializes it which includes a call to g_variant_release_children() and therefore means that any children previously retrieved from the variant are no longer valid (unless another reference is held on them) and consequently values borrowed from those children are no longer safe to access. Add a note to the g_variant_get_child_value() documentation to explain this. Alternatively, we could say that after the child is freed, values borrowed from it are no longer valid. But we already have an implementation which hasn't changed in years which lets them stay valid if the variant was serialized before the first g_variant_get_child_value() call. Here's a demonstration of the memory error: static const char *get_first_child (GVariant *v) { g_autoptr(GVariant) child_v = g_variant_get_child_value (v, 0); return g_variant_get_string (child_v, NULL); } int main(int argc, char **argv) { g_autoptr(GVariant) v = g_variant_new("(@ss)", g_variant_new_string ("hello"), "world"); const char *child1 = get_first_child (v); const char *child2; g_variant_get_child (v, 1, "&s", &child2); printf ("%s\n", child1); // this is a memory error return 0; } --- glib/gvariant-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c index f0b372f40..b2470c488 100644 --- a/glib/gvariant-core.c +++ b/glib/gvariant-core.c @@ -1026,6 +1026,12 @@ g_variant_n_children (GVariant *value) * The returned value is never floating. You should free it with * g_variant_unref() when you're done with it. * + * Note that values borrowed from the returned child are not guaranteed to + * still be valid after the child is freed even if you still hold a reference + * to @value, if @value has not been serialised at the time this function is + * called. To avoid this, you can serialize @value by calling + * g_variant_get_data() and optionally ignoring the return value. + * * There may be implementation specific restrictions on deeply nested values, * which would result in the unit tuple being returned as the child value, * instead of further nested children. #GVariant is guaranteed to handle