[at-spi2-core/gnome-3-36] Fix handling of event listener removals during an event callback



commit bc7a17b037cef3dc710b944ec49e461136a703bc
Author: Mike Gorse <mgorse suse com>
Date:   Wed Sep 2 17:11:15 2020 -0500

    Fix handling of event listener removals during an event callback
    
    We should not modify event_listeners while we are iterating through it.
    Otherwise, we may crash. If an event listener is removed from within an event
    callback, then defer the removal until the callback has ended.

 atspi/atspi-event-listener.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)
---
diff --git a/atspi/atspi-event-listener.c b/atspi/atspi-event-listener.c
index d85321cd..38271f8e 100644
--- a/atspi/atspi-event-listener.c
+++ b/atspi/atspi-event-listener.c
@@ -166,6 +166,9 @@ atspi_event_listener_new_simple (AtspiEventListenerSimpleCB callback,
 }
 
 static GList *event_listeners = NULL;
+static GList *pending_removals = NULL;
+static int in_send = 0;
+
 
 static gchar *
 convert_name_from_dbus (const char *name, gboolean path_hack)
@@ -817,7 +820,10 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback,
     {
       DBusMessage *message, *reply;
       l = g_list_next (l);
-      event_listeners = g_list_remove (event_listeners, e);
+      if (in_send)
+      pending_removals = g_list_append (pending_removals, e);
+      else
+        event_listeners = g_list_remove (event_listeners, e);
       for (i = 0; i < matchrule_array->len; i++)
       {
        char *matchrule = g_ptr_array_index (matchrule_array, i);
@@ -834,7 +840,8 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback,
       if (reply)
         dbus_message_unref (reply);
 
-      listener_entry_free (e);
+      if (!in_send)
+        listener_entry_free (e);
     }
     else
       l = g_list_next (l);
@@ -909,6 +916,13 @@ detail_matches_listener (const char *event_detail, const char *listener_detail)
                : strcmp (listener_detail, event_detail));
 }
 
+static void
+resolve_pending_removal (gpointer data)
+{
+  event_listeners = g_list_remove (event_listeners, data);
+  listener_entry_free (data);
+}
+
 void
 _atspi_send_event (AtspiEvent *e)
 {
@@ -929,6 +943,7 @@ _atspi_send_event (AtspiEvent *e)
     g_warning ("AT-SPI: Couldn't parse event: %s\n", e->type);
     return;
   }
+  in_send++;
   for (l = event_listeners; l; l = g_list_next (l))
   {
     EventListenerEntry *entry = l->data;
@@ -944,16 +959,28 @@ _atspi_send_event (AtspiEvent *e)
           break;
       }
       if (!l2)
+      {
+        for (l2 = pending_removals; l2; l2 = l2->next)
+        {
+        if (l2->data == entry)
+          break;
+        }
+      }
+      if (!l2)
       {
         entry->callback (atspi_event_copy (e), entry->user_data);
         called_listeners = g_list_prepend (called_listeners, entry);
       }
     }
   }
+  in_send--;
   if (detail) g_free (detail);
   g_free (name);
   g_free (category);
   g_list_free (called_listeners);
+
+  g_list_free_full (pending_removals, resolve_pending_removal);
+  pending_removals = NULL;
 }
 
 DBusHandlerResult


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