[mutter] clutter/actor: Do clutter_actor_destroy_all_children without an iterator



commit 3d94c7cc2d35677b193f90649304737978350d04
Author: Daniel van Vugt <daniel van vugt canonical com>
Date:   Wed Nov 3 16:35:27 2021 +0800

    clutter/actor: Do clutter_actor_destroy_all_children without an iterator
    
    `clutter_actor_iter_destroy` will try to match up the iterator's `age`
    with that of the parent ("root") actor:
    
    ```
    g_return_if_fail (ri->age == ri->root->priv->age);
    ```
    
    In a simple actor graph that's completely reasonable but somewhere in the
    more complex graph of gnome-shell the parent's `age` was skipping ahead
    faster than that of the iterator. This could happen in theory if the
    destroy indirectly leads to more children being destroyed than the
    iterator has visited.
    
    So there's no evidence of actual corruption, only the age check might
    fail in a `clutter_actor_iter_destroy` loop because the age check itself
    can't handle all possible valid scenarios.
    
    Since our only mandate is to destroy all children, we can do that reliably
    without an iterator and thus without assuming anything about the parent's
    `age` counter.
    
    Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4747
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2074>

 clutter/clutter/clutter-actor.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
---
diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
index 00f51b04fd..067666cc6c 100644
--- a/clutter/clutter/clutter-actor.c
+++ b/clutter/clutter/clutter-actor.c
@@ -12031,8 +12031,6 @@ clutter_actor_remove_all_children (ClutterActor *self)
 void
 clutter_actor_destroy_all_children (ClutterActor *self)
 {
-  ClutterActorIter iter;
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
   if (self->priv->n_children == 0)
@@ -12040,9 +12038,14 @@ clutter_actor_destroy_all_children (ClutterActor *self)
 
   g_object_freeze_notify (G_OBJECT (self));
 
-  clutter_actor_iter_init (&iter, self);
-  while (clutter_actor_iter_next (&iter, NULL))
-    clutter_actor_iter_destroy (&iter);
+  while (self->priv->first_child != NULL)
+    {
+      gint prev_n_children = self->priv->n_children;
+
+      clutter_actor_destroy (self->priv->first_child);
+
+      g_assert (self->priv->n_children < prev_n_children);
+    }
 
   g_object_thaw_notify (G_OBJECT (self));
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]