From 96d94e0076773d6b29107035dc61f5df01a3347f Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Thu, 28 Sep 2017 11:27:56 +0900 Subject: [PATCH] evas: Fix dangling references with input devices This solves issues with efl_input_dup() which didn't properly give a reference to the caller, resulting in dangling eo ids. Note: This may trigger leaks (instead of invalid refs), but this now actually reflects the meaning of @owned. This should work with bindings and C API users should know to call efl_unref(). This patch is the reason for the previous improvements on eo_debug. @fix --- src/lib/efl/interfaces/efl_common_internal.h | 2 +- src/lib/evas/canvas/efl_input_event.eo | 11 ++++++++-- src/lib/evas/canvas/efl_input_focus.c | 17 +++++++++------ src/lib/evas/canvas/efl_input_hold.c | 12 +++++----- src/lib/evas/canvas/efl_input_key.c | 7 +++--- src/lib/evas/canvas/efl_input_pointer.c | 10 ++++----- src/lib/evas/canvas/evas_device.c | 23 ++++++++++++-------- src/lib/evas/canvas/evas_focus.c | 2 +- 8 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/lib/efl/interfaces/efl_common_internal.h b/src/lib/efl/interfaces/efl_common_internal.h index 4a418cc314..a83edf1aa2 100644 --- a/src/lib/efl/interfaces/efl_common_internal.h +++ b/src/lib/efl/interfaces/efl_common_internal.h @@ -114,7 +114,7 @@ struct _Efl_Input_Focus_Data { Eo *eo; Efl_Input_Device *device; //The seat - Eo *object; //The focused object - Efl.Canvas.Object or Efl.Canvas. + Eo *object_wref; // wref on the focused object - Efl.Canvas.Object or Efl.Canvas. double timestamp; }; diff --git a/src/lib/evas/canvas/efl_input_event.eo b/src/lib/evas/canvas/efl_input_event.eo index 51679e85f9..b90f918221 100644 --- a/src/lib/evas/canvas/efl_input_event.eo +++ b/src/lib/evas/canvas/efl_input_event.eo @@ -31,8 +31,15 @@ mixin Efl.Input.Event (Efl.Interface, Efl.Object) [[Resets the internal data to 0 or default values.]] } dup @pure_virtual { - [[Creates a copy of this event.]] - return: Efl.Input.Event @owned; [[Event copy]] + [[Creates a copy of this event. + + The returned event object is similar to the given object in most + ways except that @.fake will be $true. + + Note: A reference is given to the caller. In order to avoid leaks + the C API users should call $efl_unref() after use. + ]] + return: Efl.Input.Event @owned; [[Event copy, marked as @.fake.]] } @property device @pure_virtual { [[Input device that originated this event.]] diff --git a/src/lib/evas/canvas/efl_input_focus.c b/src/lib/evas/canvas/efl_input_focus.c index 5e3065b489..cc8e64aa0a 100644 --- a/src/lib/evas/canvas/efl_input_focus.c +++ b/src/lib/evas/canvas/efl_input_focus.c @@ -39,6 +39,7 @@ _del_hook(Eo *evt) static void _efl_input_focus_free(Efl_Input_Focus_Data *pd) { + efl_wref_del_safe(&pd->object_wref); efl_unref(pd->device); } @@ -71,13 +72,13 @@ EOLIAN static void _efl_input_focus_object_set(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd, Efl_Object *object) { - pd->object = object; + pd->object_wref = object; } EOLIAN static Efl_Object * _efl_input_focus_object_get(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd) { - return pd->object; + return pd->object_wref; } EOLIAN static void @@ -111,18 +112,20 @@ _efl_input_focus_efl_input_event_timestamp_get(Eo *obj EINA_UNUSED, } EOLIAN static Efl_Input_Focus * -_efl_input_focus_efl_input_event_dup(Eo *obj, Efl_Input_Focus_Data *pd) +_efl_input_focus_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Focus_Data *pd) { Efl_Input_Focus_Data *ev; Efl_Input_Focus *evt; - evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev); - if (!evt || !ev) return NULL; + evt = efl_add(MY_CLASS, NULL); + ev = efl_data_scope_get(evt, MY_CLASS); + if (!ev) return NULL; + memcpy(ev, pd, sizeof(*ev)); ev->eo = evt; - ev->object = pd->object; ev->device = efl_ref(pd->device); - ev->timestamp = pd->timestamp; + efl_wref_add(ev->object_wref, &ev->object_wref); + return evt; } diff --git a/src/lib/evas/canvas/efl_input_hold.c b/src/lib/evas/canvas/efl_input_hold.c index 1d991e78f0..beca304098 100644 --- a/src/lib/evas/canvas/efl_input_hold.c +++ b/src/lib/evas/canvas/efl_input_hold.c @@ -101,17 +101,19 @@ _efl_input_hold_efl_input_event_reset(Eo *obj, Efl_Input_Hold_Data *pd) } EOLIAN static Efl_Input_Event * -_efl_input_hold_efl_input_event_dup(Eo *obj, Efl_Input_Hold_Data *pd) +_efl_input_hold_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Hold_Data *pd) { Efl_Input_Hold_Data *ev; - Efl_Input_Event *evt = efl_add(EFL_INPUT_HOLD_CLASS, efl_parent_get(obj)); + Efl_Input_Hold *evt; + + evt = efl_add(MY_CLASS, NULL); ev = efl_data_scope_get(evt, MY_CLASS); if (!ev) return NULL; + memcpy(ev, pd, sizeof(*ev)); ev->eo = evt; - ev->timestamp = pd->timestamp; - ev->data = pd->data; - ev->hold = pd->hold; + ev->legacy = NULL; + ev->evas_done = 0; ev->device = efl_ref(pd->device); return evt; diff --git a/src/lib/evas/canvas/efl_input_key.c b/src/lib/evas/canvas/efl_input_key.c index d4154ce963..052b971b3f 100644 --- a/src/lib/evas/canvas/efl_input_key.c +++ b/src/lib/evas/canvas/efl_input_key.c @@ -188,13 +188,14 @@ _efl_input_key_efl_input_event_reset(Eo *obj EINA_UNUSED, Efl_Input_Key_Data *pd } EOLIAN static Efl_Input_Event * -_efl_input_key_efl_input_event_dup(Eo *obj, Efl_Input_Key_Data *pd) +_efl_input_key_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Key_Data *pd) { Efl_Input_Key_Data *ev; Efl_Input_Key *evt; - evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev); - if (!evt || !ev) return NULL; + evt = efl_add(MY_CLASS, NULL); + ev = efl_data_scope_get(evt, MY_CLASS); + if (!ev) return NULL; memcpy(ev, pd, sizeof(*ev)); ev->eo = evt; diff --git a/src/lib/evas/canvas/efl_input_pointer.c b/src/lib/evas/canvas/efl_input_pointer.c index 6e95a11bc0..ec5834183b 100644 --- a/src/lib/evas/canvas/efl_input_pointer.c +++ b/src/lib/evas/canvas/efl_input_pointer.c @@ -143,13 +143,14 @@ _efl_input_pointer_efl_input_event_reset(Eo *obj, Efl_Input_Pointer_Data *pd) } EOLIAN static Efl_Input_Event * -_efl_input_pointer_efl_input_event_dup(Eo *obj, Efl_Input_Pointer_Data *pd) +_efl_input_pointer_efl_input_event_dup(Eo *obj EINA_UNUSED, Efl_Input_Pointer_Data *pd) { Efl_Input_Pointer_Data *ev; - Efl_Input_Pointer *evt; + Efl_Input_Focus *evt; - evt = efl_input_instance_get(MY_CLASS, efl_parent_get(obj), (void **) &ev); - if (!evt) return NULL; + evt = efl_add(MY_CLASS, NULL); + ev = efl_data_scope_get(evt, MY_CLASS); + if (!ev) return NULL; memcpy(ev, pd, sizeof(*ev)); ev->eo = evt; @@ -157,7 +158,6 @@ _efl_input_pointer_efl_input_event_dup(Eo *obj, Efl_Input_Pointer_Data *pd) ev->evas_done = 0; ev->win_fed = 0; ev->fake = 1; - ev->legacy = NULL; ev->device = efl_ref(pd->device); return evt; diff --git a/src/lib/evas/canvas/evas_device.c b/src/lib/evas/canvas/evas_device.c index 7f93b77801..9c740c0e0a 100644 --- a/src/lib/evas/canvas/evas_device.c +++ b/src/lib/evas/canvas/evas_device.c @@ -460,7 +460,7 @@ evas_device_seat_id_get(const Evas_Device *dev) void _evas_device_cleanup(Evas *eo_e) { - Eina_List *cpy; + Eina_List *cpy, *deleted = NULL; Evas_Device *dev; Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS); @@ -473,19 +473,26 @@ _evas_device_cleanup(Evas *eo_e) } /* If the device is deleted, _del_cb will remove the device - from the devices list. */ + * from the devices list. Ensure we delete them only once, and only if this + * Evas is the owner, otherwise we would kill external references (eg. + * from efl_input_dup()). */ again: e->devices_modified = EINA_FALSE; cpy = eina_list_clone(e->devices); EINA_LIST_FREE(cpy, dev) { - evas_device_del(dev); - if (e->devices_modified) + if (!eina_list_data_find(deleted, dev) && (efl_parent_get(dev) == eo_e)) { - eina_list_free(cpy); - goto again; + evas_device_del(dev); + deleted = eina_list_append(deleted, dev); + if (e->devices_modified) + { + eina_list_free(cpy); + goto again; + } } } + eina_list_free(deleted); /* Not all devices were deleted. The user probably will unref them later. Since Evas will be deleted, remove the del callback from them and @@ -493,9 +500,7 @@ again: */ EINA_LIST_FREE(e->devices, dev) { - efl_event_callback_call(e->evas, - EFL_CANVAS_EVENT_DEVICE_REMOVED, - dev); + efl_event_callback_call(e->evas, EFL_CANVAS_EVENT_DEVICE_REMOVED, dev); efl_event_callback_del(dev, EFL_EVENT_DEL, _del_cb, e); } } diff --git a/src/lib/evas/canvas/evas_focus.c b/src/lib/evas/canvas/evas_focus.c index 6fc1ebaad2..17e38a4693 100644 --- a/src/lib/evas/canvas/evas_focus.c +++ b/src/lib/evas/canvas/evas_focus.c @@ -80,7 +80,7 @@ _evas_focus_dispatch_event(Evas_Object_Protected_Data *obj, Efl_Input_Device *se if (!evt) return; ev_data->device = efl_ref(seat); - ev_data->object = obj->object; + efl_wref_add(obj->object, &ev_data->object_wref); ev_data->timestamp = time(NULL); if (in)