From 261447a498e8ef3db40c4d30d5e08ec87daa43d3 Mon Sep 17 00:00:00 2001 From: Daniel van Vugt Date: Mon, 30 Nov 2020 18:03:01 +0800 Subject: [PATCH] clutter/stage: Steal and manually free pending_queue_redraw entries New entries indirectly added to `pending_queue_redraw` during the loop would make our iterator invalid and cause `g_hash_table_iter_next` to fail without having visited all elements. That was seen as assertion failures but also likely resulted in incomplete paint clips. Now we steal the iterator's entry before such corruption can happen, free it manually, and reset the iterator to the beginning on every iteration. This is actually safe and efficient because we're removing each entry we visit. So no time is wasted in resuming from the (new) beginning of the hash table. Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1557 Part-of: --- clutter/clutter/clutter-stage.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index fd12c0381..626193e2a 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -2800,6 +2800,8 @@ clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage) QueueRedrawEntry *entry = value; ClutterPaintVolume old_actor_pv, new_actor_pv; + g_hash_table_iter_steal (&iter); + _clutter_paint_volume_init_static (&old_actor_pv, NULL); _clutter_paint_volume_init_static (&new_actor_pv, NULL); @@ -2829,7 +2831,15 @@ clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage) add_to_stage_clip (stage, NULL); } - g_hash_table_iter_remove (&iter); + g_object_unref (redraw_actor); + free_queue_redraw_entry (entry); + + /* get_paint_volume() vfuncs might queue redraws and can cause our + * iterator to now be invalidated. So start over. This isn't wasting + * any time since we already stole (removed) the elements previously + * visited. + */ + g_hash_table_iter_init (&iter, priv->pending_queue_redraws); } }