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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1615>
This commit is contained in:
Daniel van Vugt 2020-11-30 18:03:01 +08:00
parent 2f01ef69e3
commit 261447a498

View File

@ -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);
}
}