GtkVariant and iterating over list of dictionaries

I am trying to iterate over a GtkVariant which is of the format “aa{uv}”. The top level structure is a list where each of the elements in that list is a dictionary.

The string representing that structure get’s successfully parsed (using g_variant_parse()). However, I can’t seem to get the element in the array working. I am using the following code:

GVariant *variant, *elem = NULL;
GVariantIter iter;
GError *error = NULL;

variant = g_variant_parse(G_VARIANT_TYPE("aa{uv}"), data,
			  data + strlen(data), NULL, &error);
if (!variant) {
	warning("Failed to parse data: %s", error->message);
	g_error_free(error);
	return;
}
g_variant_ref_sink(variant);
printf("data type: %s\n", g_variant_get_type_string(variant));
g_variant_iter_init(&iter, variant);
while (g_variant_iter_next(&iter, "a{uv}", &elem)) {
	printf("%p %s\n", elem, g_variant_get_type_string(elem));
	g_variant_unref(elem);
}

The above code generates a abort (as a result of a call to g_error()) in the call to g_variant_get_type_string(elem) with the following output:

data type: aa{uv}
**
GLib:ERROR:…/…/…/…/glib/gvarianttypeinfo.c:163:g_variant_type_info_check: assertion failed: (info->alignment == 0 || info->alignment == 1 || info->alignment == 3 || info->alignment == 7)

Can someone help me understand where I am going wrong?
Thank you

Can you give a minimal reproducer which includes the allocation and instantiation of data please?

Here you go:

#include <glib.h>
#include <stdio.h>

int main(void) {
    const gchar data[] = "[{uint32 2959077576: <{'a': <(uint32 1, uint32 71, 'test1')>, 'b': <[{uint32 580176270: <{'c': <(uint32 0, uint32 3, 'test2')>, 'b': <@aa{uv} []>}>}]>}>}]";
    GVariant *variant, *elem = NULL;
    GVariantIter iter;
    GError *error = NULL;

    variant = g_variant_parse(G_VARIANT_TYPE("aa{uv}"), data,
                        data + strlen(data), NULL, &error);
    if (!variant) {
        g_warning("Failed to parse data: %s", error->message);
        g_error_free(error);
        return -1;
    }
    g_variant_ref_sink(variant);
    printf("data type: %s\n", g_variant_get_type_string(variant));
    g_variant_iter_init(&iter, variant);
    while (g_variant_iter_next(&iter, "a{uv}", &elem)) {
         printf("%p %s\n", elem, g_variant_get_type_string(elem));
         g_variant_unref(elem);
    }
    return 0;
}

I have to run now, but try ensuring that data is aligned on an 8-byte boundary. You can use malloc() to do this.

Philip

Changing the declaration of data to:

 const gchar data[] __attribute__((aligned(8))) = "[{uint32 2959077576: <{'a': <(uint32 1, uint32 71, 'test1')>, 'b': <[{uint32 580176270: <{'c': <(uint32 0, uint32 3, 'test2')>, 'b': <@aa{uv} []>}>}]>}>}]";

and aligning it on an 8 byte boundary doesn’t work.

If you just want the value as a GVariant, you might try g_variant_iter_next_value() instead of g_variant_iter_next().

So, what the difference? From the documentation, it seem that both calls set the elem GVariant to the same thing.

Having played with it a little this morning, this looks like it’s potentially a bug in GVariant. Would you mind filing a bug in GitLab about it please, attaching your minimal reproducer, and someone can take a look? Otherwise it’ll get lost on Discourse. Thanks.

Issue has been submitted: https://gitlab.gnome.org/GNOME/glib/issues/1731

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.