bdilly pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=402abcaefca02973c384d7c37fe543837d566443

commit 402abcaefca02973c384d7c37fe543837d566443
Author: Guilherme Iscaro <isc...@profusion.mobi>
Date:   Tue Nov 1 16:03:52 2016 -0200

    Evas Device: Avoid invalid ptr indirection.
    
    Summary:
    When Evas is deleted the function _evas_device_cleanup() goes thru all
    devices and unref them. Since Evas_Devices are Efl_Input_Device, the user
    may still hold a reference to the device (efl_ref()),
    thus causing the device to do not be deleted *yet*.
    This causes a problem, because when the user calls efl_unref()
    and the device itself is deleted the Evas _del_cb
    callback will be called and will try to access the Evas_Public_Data from
    a deleted object.
    In order to avoid this problem all devices will be kept in the devices
    list and Evas will unregister the EFL_EVENT_DEL from those devices that
    were not deleted.
    
    Reviewers: jpeg, bdilly, barbieri, cedric
    
    Reviewed By: bdilly, cedric
    
    Subscribers: cedric, jpeg
    
    Differential Revision: https://phab.enlightenment.org/D4369
---
 src/lib/evas/canvas/evas_device.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/lib/evas/canvas/evas_device.c 
b/src/lib/evas/canvas/evas_device.c
index bea2ad7..f243b89 100644
--- a/src/lib/evas/canvas/evas_device.c
+++ b/src/lib/evas/canvas/evas_device.c
@@ -66,8 +66,7 @@ evas_device_add_full(Evas *eo_e, const char *name, const char 
*desc,
    d->evas = eo_e;
 
    e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
-   if (!parent_dev)
-     e->devices = eina_list_append(e->devices, dev);
+   e->devices = eina_list_append(e->devices, dev);
    efl_event_callback_add(dev, EFL_EVENT_DEL, _del_cb, e);
 
    efl_event_callback_call(eo_e, EFL_CANVAS_EVENT_DEVICE_ADDED, dev);
@@ -170,17 +169,12 @@ evas_device_parent_set(Evas_Device *dev, Evas_Device 
*parent)
    SAFETY_CHECK(dev, EFL_INPUT_DEVICE_CLASS);
 
    Efl_Input_Device_Data *d = efl_data_scope_get(dev, EFL_INPUT_DEVICE_CLASS);
-   Evas_Public_Data *e = efl_data_scope_get(d->evas, EVAS_CANVAS_CLASS);
    if (parent)
      {
         SAFETY_CHECK(parent, EFL_INPUT_DEVICE_CLASS);
      }
 
    efl_input_device_parent_set(dev, parent);
-   if (parent)
-     e->devices = eina_list_remove(e->devices, dev);
-   else
-     e->devices = eina_list_append(e->devices, dev);
    evas_event_callback_call(d->evas, EVAS_CALLBACK_DEVICE_CHANGED, dev);
 }
 
@@ -242,9 +236,10 @@ evas_device_emulation_source_get(const Evas_Device *dev)
 void
 _evas_device_cleanup(Evas *eo_e)
 {
+   Eina_List *cpy;
    Evas_Device *dev;
-   
    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
+
    if (e->cur_device)
      {
         while ((dev = eina_array_pop(e->cur_device)))
@@ -252,9 +247,23 @@ _evas_device_cleanup(Evas *eo_e)
         eina_array_free(e->cur_device);
         e->cur_device = NULL;
      }
+
+   /* If the device is deleted, _del_cb will remove the device
+      from the devices list. */
+   cpy = eina_list_clone(e->devices);
+   EINA_LIST_FREE(cpy, dev)
+     evas_device_del(dev);
+
+   /* Not all devices were deleted. The user probably will unref them later.
+      Since Evas will be deleted, remove the del callback from them and
+      tell the user that the device was removed.
+   */
    EINA_LIST_FREE(e->devices, dev)
      {
-        evas_device_del(dev);
+        efl_event_callback_call(e->evas,
+                                EFL_CANVAS_EVENT_DEVICE_REMOVED,
+                                dev);
+        efl_event_callback_del(dev, EFL_EVENT_DEL, _del_cb, e);
      }
 }
 

-- 


Reply via email to