diff --git a/modulemd/meson.build b/modulemd/meson.build index e927d43c..d58ea8f1 100644 --- a/modulemd/meson.build +++ b/modulemd/meson.build @@ -365,6 +365,7 @@ c_tests = { 'service_level' : [ 'tests/test-modulemd-service-level.c' ], 'translation' : [ 'tests/test-modulemd-translation.c' ], 'translation_entry' : [ 'tests/test-modulemd-translation-entry.c' ], +'variant_deep_copy' : [ 'tests/test-modulemd-variant_deep_copy.c' ], 'obsoletes' : [ 'tests/test-modulemd-obsoletes.c' ], 'quoting' : [ 'tests/test-modulemd-quoting.c' ], } diff --git a/modulemd/modulemd-util.c b/modulemd/modulemd-util.c index 99a5c53f..535519eb 100644 --- a/modulemd/modulemd-util.c +++ b/modulemd/modulemd-util.c @@ -363,9 +363,13 @@ modulemd_variant_deep_copy (GVariant *variant) { const GVariantType *data_type = g_variant_get_type (variant); gsize data_size = g_variant_get_size (variant); - gpointer data = g_malloc0 (data_size); + gpointer data = NULL; - g_variant_store (variant, data); + if (data_size > 0) + { + data = g_malloc0 (data_size); + g_variant_store (variant, data); + } return g_variant_ref_sink (g_variant_new_from_data ( data_type, data, data_size, FALSE, destroy_variant_data, data)); diff --git a/modulemd/tests/test-modulemd-variant_deep_copy.c b/modulemd/tests/test-modulemd-variant_deep_copy.c new file mode 100644 index 00000000..279136c0 --- /dev/null +++ b/modulemd/tests/test-modulemd-variant_deep_copy.c @@ -0,0 +1,69 @@ +/* + * This file is part of libmodulemd + * Copyright (C) 2025 Red Hat, Inc. + * + * Fedora-License-Identifier: MIT + * SPDX-2.0-License-Identifier: MIT + * SPDX-3.0-License-Identifier: MIT + * + * This program is free software. + * For more information on the license, see COPYING. + * For more information on free software, see . + */ + +#include +#include +#include +#include + +#include "private/modulemd-util.h" + +/* + * modulemd_variant_deep_copy() triggered a GLib critical warning + * from glib >= 2.84.1 when parsing a /data/xmd modulemd-stream-v2 element + * with {} value (an empty flow mapping). This test exhibits that code path + * and relies on G_DEBUG=fatal-criticals environment variable to crash the + * test. + * . + */ +static void +test_empty_a_sv (void) +{ + g_autoptr (GVariantDict) dictionary = + NULL; /* g_variant_dict_end() does not free */ + g_autoptr (GVariant) input = NULL; + g_autoptr (GVariant) output = NULL; + + /* Build a GVariant with an empty dictionary, results to an "a{sv}" of + * zero size. */ + dictionary = g_variant_dict_new (NULL); + input = g_variant_dict_end (dictionary); + + /* Exhibit the library. */ + output = modulemd_variant_deep_copy (input); + g_assert_true (output != NULL); + + /* Compare the content. */ + g_assert_true (g_variant_get_type (output) == g_variant_get_type (input)); + g_assert_true (g_variant_get_size (output) == g_variant_get_size (input)); +} + + +int +main (int argc, char *argv[]) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + g_test_set_nonfatal_assertions (); + + if (!g_setenv ("G_DEBUG", "fatal-criticals", TRUE)) + { + g_fprintf (stderr, "Failed to set G_DEBUG environment variable.\n"); + exit (EXIT_FAILURE); + } + + g_test_add_func ("/modulemd/util/variant_deep_copy/empty_a{sv}", + test_empty_a_sv); + + return g_test_run (); +}