From ec9a73a2622bec15bde91d11b886ca5b05399e25 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 14 Feb 2024 11:51:08 +0000 Subject: [PATCH] gibaseinfo: Allow gi_base_info_clear() to be idempotent When called on an already-cleared `GIBaseInfo` it should do nothing. Signed-off-by: Philip Withnall Fixes: #3255 --- girepository/gibaseinfo.c | 11 +++++++++- girepository/tests/repository.c | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/girepository/gibaseinfo.c b/girepository/gibaseinfo.c index d24cd4aa8..ccc5aed37 100644 --- a/girepository/gibaseinfo.c +++ b/girepository/gibaseinfo.c @@ -443,7 +443,9 @@ gi_info_init (GIRealInfo *info, * Clears memory allocated internally by a stack-allocated * [type@GIRepository.BaseInfo]. * - * This does not deallocate the [type@GIRepository.BaseInfo] struct itself. + * This does not deallocate the [type@GIRepository.BaseInfo] struct itself. It + * does clear the struct to zero so that calling this function subsequent times + * on the same struct is a no-op. * * This must only be called on stack-allocated [type@GIRepository.BaseInfo]s. * Use [method@GIRepository.BaseInfo.unref] for heap-allocated ones. @@ -455,6 +457,11 @@ gi_base_info_clear (void *info) { GIBaseInfo *rinfo = (GIBaseInfo *) info; + /* If @info is zero-filled, do nothing. This allows gi_base_info_clear() to be + * used with g_auto(). */ + if (rinfo->ref_count == 0) + return; + g_return_if_fail (GI_IS_BASE_INFO (rinfo)); g_assert (rinfo->ref_count == INVALID_REFCOUNT); @@ -462,6 +469,8 @@ gi_base_info_clear (void *info) GI_BASE_INFO_GET_CLASS (info)->finalize (rinfo); g_type_class_unref (rinfo->parent_instance.g_class); + + memset (rinfo, 0, sizeof (*rinfo)); } GIBaseInfo * diff --git a/girepository/tests/repository.c b/girepository/tests/repository.c index 506726375..565023147 100644 --- a/girepository/tests/repository.c +++ b/girepository/tests/repository.c @@ -156,6 +156,42 @@ test_repository_dependencies (RepositoryFixture *fx, g_clear_pointer (&dependencies, g_strfreev); } +static void +test_repository_base_info_clear (RepositoryFixture *fx, + const void *unused) +{ + GITypeInfo zeroed_type_info = { 0, }; + GITypeInfo idempotent_type_info; + GIObjectInfo *object_info = NULL; + GIFunctionInfo *method_info = NULL; + GIArgInfo *arg_info = NULL; + + g_test_summary ("Test calling gi_base_info_clear() on a zero-filled struct"); + + /* Load a valid #GITypeInfo onto the stack and clear it multiple times to + * check gi_base_info_clear() is idempotent after the first call. */ + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Object")); + g_assert_nonnull (object_info); + method_info = gi_object_info_find_method (object_info, "get_property"); + g_assert_nonnull (method_info); + arg_info = gi_callable_info_get_arg (GI_CALLABLE_INFO (method_info), 0); + g_assert_nonnull (arg_info); + gi_arg_info_load_type_info (arg_info, &idempotent_type_info); + + gi_base_info_clear (&idempotent_type_info); + gi_base_info_clear (&idempotent_type_info); + gi_base_info_clear (&idempotent_type_info); + + g_clear_pointer (&arg_info, gi_base_info_unref); + g_clear_pointer (&method_info, gi_base_info_unref); + g_clear_pointer (&object_info, gi_base_info_unref); + + /* Try clearing a #GITypeInfo which has always been zero-filled on the stack. */ + gi_base_info_clear (&zeroed_type_info); + gi_base_info_clear (&zeroed_type_info); + gi_base_info_clear (&zeroed_type_info); +} + static void test_repository_arg_info (RepositoryFixture *fx, const void *unused) @@ -750,6 +786,7 @@ main (int argc, ADD_REPOSITORY_TEST ("/repository/basic", test_repository_basic, &typelib_load_spec_glib); ADD_REPOSITORY_TEST ("/repository/info", test_repository_info, &typelib_load_spec_gobject); ADD_REPOSITORY_TEST ("/repository/dependencies", test_repository_dependencies, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/base-info/clear", test_repository_base_info_clear, &typelib_load_spec_gobject); ADD_REPOSITORY_TEST ("/repository/arg-info", test_repository_arg_info, &typelib_load_spec_gobject); ADD_REPOSITORY_TEST ("/repository/callable-info", test_repository_callable_info, &typelib_load_spec_gobject); ADD_REPOSITORY_TEST ("/repository/callback-info", test_repository_callback_info, &typelib_load_spec_gobject);