clutter/cally-actor: Ensure accessible lives long enough

Inside the "if (clutter_actor_has_accessible (actor))" condition,
the 'atk_child' variable is set and a signal is emitted on it.
There is a classic ref/unref dance around the signal to guarantee
that 'atk_child' won't be destroyed.

However, this ref/unref dance doesn't work, because the unref is
done *before* the 'atk_child' variable is used again. So if this
was the last reference to it, it would have been destroyed in the
unref call, then used for another signal emission a few lines down.

That's a use-after-free.

Fix that by declaring the 'atk_child' variable with g_autoptr. This
delays the unref until the very end of the function, and is NULL safe.
Also add a sneaky assertion, just for extra safety.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3828>
This commit is contained in:
Georges Basile Stavracas Neto 2024-06-20 17:05:42 -03:00 committed by Marge Bot
parent e4c749e5f2
commit 5cfbe2528c

View File

@ -474,9 +474,9 @@ cally_actor_remove_actor (ClutterActor *container,
ClutterActor *actor, ClutterActor *actor,
gpointer data) gpointer data)
{ {
g_autoptr (AtkObject) atk_child = NULL;
AtkPropertyValues values = { NULL }; AtkPropertyValues values = { NULL };
AtkObject *atk_parent = NULL; AtkObject *atk_parent = NULL;
AtkObject *atk_child = NULL;
CallyActorPrivate *priv = NULL; CallyActorPrivate *priv = NULL;
gint index; gint index;
@ -489,15 +489,16 @@ cally_actor_remove_actor (ClutterActor *container,
{ {
atk_child = clutter_actor_get_accessible (actor); atk_child = clutter_actor_get_accessible (actor);
g_assert (ATK_IS_OBJECT (atk_child));
g_object_ref (atk_child);
g_value_init (&values.old_value, G_TYPE_POINTER); g_value_init (&values.old_value, G_TYPE_POINTER);
g_value_set_pointer (&values.old_value, atk_parent); g_value_set_pointer (&values.old_value, atk_parent);
values.property_name = "accessible-parent"; values.property_name = "accessible-parent";
g_object_ref (atk_child);
g_signal_emit_by_name (atk_child, g_signal_emit_by_name (atk_child,
"property_change::accessible-parent", &values, NULL); "property_change::accessible-parent", &values, NULL);
g_object_unref (atk_child);
} }
priv = cally_actor_get_instance_private (CALLY_ACTOR (atk_parent)); priv = cally_actor_get_instance_private (CALLY_ACTOR (atk_parent));