Blame SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch

79df40
From dfd79cf19dcebf283bd884dded8efc83e449016d Mon Sep 17 00:00:00 2001
79df40
From: Olivier Fourdan <ofourdan@redhat.com>
79df40
Date: Mon, 19 Nov 2018 11:25:57 +0100
79df40
Subject: [PATCH 07/28] clutter: Keep a device reference with events
79df40
79df40
If a device (virtual or real) is removed while there are remaining
79df40
events queued for that device, the event loop may try to access the
79df40
event freed memory.
79df40
79df40
To avoid the issue, add a reference to the device when the event is
79df40
created or copied, and remove the reference once the device is freed.
79df40
79df40
Closes: https://gitlab.gnome.org/GNOME/mutter/issues/393
79df40
---
79df40
 clutter/clutter/clutter-event.c | 16 ++++++++++++----
79df40
 1 file changed, 12 insertions(+), 4 deletions(-)
79df40
79df40
diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c
79df40
index 10b6c0082..1b21b6a97 100644
79df40
--- a/clutter/clutter/clutter-event.c
79df40
+++ b/clutter/clutter/clutter-event.c
79df40
@@ -1068,61 +1068,61 @@ clutter_event_get_device_type (const ClutterEvent *event)
79df40
 
79df40
   g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE);
79df40
 
79df40
   device = clutter_event_get_device (event);
79df40
   if (device != NULL)
79df40
     return clutter_input_device_get_device_type (device);
79df40
 
79df40
   return CLUTTER_POINTER_DEVICE;
79df40
 }
79df40
 
79df40
 /**
79df40
  * clutter_event_set_device:
79df40
  * @event: a #ClutterEvent
79df40
  * @device: (allow-none): a #ClutterInputDevice, or %NULL
79df40
  *
79df40
  * Sets the device for @event.
79df40
  *
79df40
  * Since: 1.6
79df40
  */
79df40
 void
79df40
 clutter_event_set_device (ClutterEvent       *event,
79df40
                           ClutterInputDevice *device)
79df40
 {
79df40
   g_return_if_fail (event != NULL);
79df40
   g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
79df40
 
79df40
   if (is_event_allocated (event))
79df40
     {
79df40
       ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
79df40
 
79df40
-      real_event->device = device;
79df40
+      g_set_object (&real_event->device, device);
79df40
     }
79df40
 
79df40
   switch (event->type)
79df40
     {
79df40
     case CLUTTER_NOTHING:
79df40
     case CLUTTER_STAGE_STATE:
79df40
     case CLUTTER_DESTROY_NOTIFY:
79df40
     case CLUTTER_CLIENT_MESSAGE:
79df40
     case CLUTTER_DELETE:
79df40
     case CLUTTER_EVENT_LAST:
79df40
       break;
79df40
 
79df40
     case CLUTTER_ENTER:
79df40
     case CLUTTER_LEAVE:
79df40
       event->crossing.device = device;
79df40
       break;
79df40
 
79df40
     case CLUTTER_BUTTON_PRESS:
79df40
     case CLUTTER_BUTTON_RELEASE:
79df40
       event->button.device = device;
79df40
       break;
79df40
 
79df40
     case CLUTTER_MOTION:
79df40
       event->motion.device = device;
79df40
       break;
79df40
 
79df40
     case CLUTTER_SCROLL:
79df40
       event->scroll.device = device;
79df40
       break;
79df40
 
79df40
@@ -1337,62 +1337,62 @@ clutter_event_new (ClutterEventType type)
79df40
   return new_event;
79df40
 }
79df40
 
79df40
 /**
79df40
  * clutter_event_copy:
79df40
  * @event: A #ClutterEvent.
79df40
  *
79df40
  * Copies @event.
79df40
  *
79df40
  * Return value: (transfer full): A newly allocated #ClutterEvent
79df40
  */
79df40
 ClutterEvent *
79df40
 clutter_event_copy (const ClutterEvent *event)
79df40
 {
79df40
   ClutterEvent *new_event;
79df40
   ClutterEventPrivate *new_real_event;
79df40
   ClutterInputDevice *device;
79df40
   gint n_axes = 0;
79df40
 
79df40
   g_return_val_if_fail (event != NULL, NULL);
79df40
 
79df40
   new_event = clutter_event_new (CLUTTER_NOTHING);
79df40
   new_real_event = (ClutterEventPrivate *) new_event;
79df40
 
79df40
   *new_event = *event;
79df40
 
79df40
   if (is_event_allocated (event))
79df40
     {
79df40
       ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
79df40
 
79df40
-      new_real_event->device = real_event->device;
79df40
-      new_real_event->source_device = real_event->source_device;
79df40
+      g_set_object (&new_real_event->device, real_event->device);
79df40
+      g_set_object (&new_real_event->source_device, real_event->source_device);
79df40
       new_real_event->delta_x = real_event->delta_x;
79df40
       new_real_event->delta_y = real_event->delta_y;
79df40
       new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
79df40
       new_real_event->base_state = real_event->base_state;
79df40
       new_real_event->button_state = real_event->button_state;
79df40
       new_real_event->latched_state = real_event->latched_state;
79df40
       new_real_event->locked_state = real_event->locked_state;
79df40
       new_real_event->tool = real_event->tool;
79df40
     }
79df40
 
79df40
   device = clutter_event_get_device (event);
79df40
   if (device != NULL)
79df40
     n_axes = clutter_input_device_get_n_axes (device);
79df40
 
79df40
   switch (event->type)
79df40
     {
79df40
     case CLUTTER_BUTTON_PRESS:
79df40
     case CLUTTER_BUTTON_RELEASE:
79df40
       if (event->button.axes != NULL)
79df40
         new_event->button.axes = g_memdup (event->button.axes,
79df40
                                            sizeof (gdouble) * n_axes);
79df40
       break;
79df40
 
79df40
     case CLUTTER_SCROLL:
79df40
       if (event->scroll.axes != NULL)
79df40
         new_event->scroll.axes = g_memdup (event->scroll.axes,
79df40
                                            sizeof (gdouble) * n_axes);
79df40
       break;
79df40
 
79df40
     case CLUTTER_MOTION:
79df40
@@ -1408,60 +1408,68 @@ clutter_event_copy (const ClutterEvent *event)
79df40
       if (event->touch.axes != NULL)
79df40
         new_event->touch.axes = g_memdup (event->touch.axes,
79df40
                                           sizeof (gdouble) * n_axes);
79df40
       break;
79df40
 
79df40
     default:
79df40
       break;
79df40
     }
79df40
 
79df40
   if (is_event_allocated (event))
79df40
     _clutter_backend_copy_event_data (clutter_get_default_backend (),
79df40
                                       event,
79df40
                                       new_event);
79df40
 
79df40
   return new_event;
79df40
 }
79df40
 
79df40
 /**
79df40
  * clutter_event_free:
79df40
  * @event: A #ClutterEvent.
79df40
  *
79df40
  * Frees all resources used by @event.
79df40
  */
79df40
 void
79df40
 clutter_event_free (ClutterEvent *event)
79df40
 {
79df40
   if (G_LIKELY (event != NULL))
79df40
     {
79df40
       _clutter_backend_free_event_data (clutter_get_default_backend (), event);
79df40
 
79df40
+      if (is_event_allocated (event))
79df40
+        {
79df40
+          ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
79df40
+
79df40
+          g_clear_object (&real_event->device);
79df40
+          g_clear_object (&real_event->source_device);
79df40
+        }
79df40
+
79df40
       switch (event->type)
79df40
         {
79df40
         case CLUTTER_BUTTON_PRESS:
79df40
         case CLUTTER_BUTTON_RELEASE:
79df40
           g_free (event->button.axes);
79df40
           break;
79df40
 
79df40
         case CLUTTER_MOTION:
79df40
           g_free (event->motion.axes);
79df40
           break;
79df40
 
79df40
         case CLUTTER_SCROLL:
79df40
           g_free (event->scroll.axes);
79df40
           break;
79df40
 
79df40
         case CLUTTER_TOUCH_BEGIN:
79df40
         case CLUTTER_TOUCH_UPDATE:
79df40
         case CLUTTER_TOUCH_END:
79df40
         case CLUTTER_TOUCH_CANCEL:
79df40
           g_free (event->touch.axes);
79df40
           break;
79df40
 
79df40
         default:
79df40
           break;
79df40
         }
79df40
 
79df40
       g_hash_table_remove (all_events, event);
79df40
       g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
79df40
     }
79df40
 }
79df40
@@ -1662,61 +1670,61 @@ clutter_event_get_source_device (const ClutterEvent *event)
79df40
   if (real_event->source_device != NULL)
79df40
     return real_event->source_device;
79df40
 
79df40
   return clutter_event_get_device (event);
79df40
 }
79df40
 
79df40
 /**
79df40
  * clutter_event_set_source_device:
79df40
  * @event: a #ClutterEvent
79df40
  * @device: (allow-none): a #ClutterInputDevice
79df40
  *
79df40
  * Sets the source #ClutterInputDevice for @event.
79df40
  *
79df40
  * The #ClutterEvent must have been created using clutter_event_new().
79df40
  *
79df40
  * Since: 1.8
79df40
  */
79df40
 void
79df40
 clutter_event_set_source_device (ClutterEvent       *event,
79df40
                                  ClutterInputDevice *device)
79df40
 {
79df40
   ClutterEventPrivate *real_event;
79df40
 
79df40
   g_return_if_fail (event != NULL);
79df40
   g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
79df40
 
79df40
   if (!is_event_allocated (event))
79df40
     return;
79df40
 
79df40
   real_event = (ClutterEventPrivate *) event;
79df40
-  real_event->source_device = device;
79df40
+  g_set_object (&real_event->source_device, device);
79df40
 }
79df40
 
79df40
 /**
79df40
  * clutter_event_get_axes:
79df40
  * @event: a #ClutterEvent
79df40
  * @n_axes: (out): return location for the number of axes returned
79df40
  *
79df40
  * Retrieves the array of axes values attached to the event.
79df40
  *
79df40
  * Return value: (transfer none): an array of axis values
79df40
  *
79df40
  * Since: 1.6
79df40
  */
79df40
 gdouble *
79df40
 clutter_event_get_axes (const ClutterEvent *event,
79df40
                         guint              *n_axes)
79df40
 {
79df40
   gdouble *retval = NULL;
79df40
   guint len = 0;
79df40
 
79df40
   switch (event->type)
79df40
     {
79df40
     case CLUTTER_NOTHING:
79df40
     case CLUTTER_STAGE_STATE:
79df40
     case CLUTTER_DESTROY_NOTIFY:
79df40
     case CLUTTER_CLIENT_MESSAGE:
79df40
     case CLUTTER_DELETE:
79df40
     case CLUTTER_ENTER:
79df40
     case CLUTTER_LEAVE:
79df40
     case CLUTTER_KEY_PRESS:
79df40
-- 
79df40
2.26.2
79df40