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