jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=100a7006b855fe4da2c2a5c1c4ec58e06b3a0bc0

commit 100a7006b855fe4da2c2a5c1c4ec58e06b3a0bc0
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Thu Jan 28 12:18:34 2016 +0900

    Evas clip: Fix rare crash in _render_pre_clipper_change
    
    Use delete callback instead of direct call to clip_unset,
    which lets us know that clip_unset() is called during the
    clipper's deletion, as opposed to a simple call.
    
    We can then make sure that the previous object state does
    not point to invalid data anymore.
    
    Here is a scenario that could have crashed:
    - load and show an edje object, hide it
    - change its theme or style
    - show it again
    
    @fix
---
 src/lib/evas/canvas/evas_clip.c        | 68 ++++++++++++++++++++++++++++------
 src/lib/evas/canvas/evas_object_main.c | 20 +++++++---
 src/lib/evas/include/evas_private.h    |  1 +
 3 files changed, 71 insertions(+), 18 deletions(-)

diff --git a/src/lib/evas/canvas/evas_clip.c b/src/lib/evas/canvas/evas_clip.c
index 874beb8..c7767db 100644
--- a/src/lib/evas/canvas/evas_clip.c
+++ b/src/lib/evas/canvas/evas_clip.c
@@ -213,6 +213,8 @@ _evas_object_clip_mask_unset(Evas_Object_Protected_Data 
*obj)
 extern const char *o_rect_type;
 extern const char *o_image_type;
 
+static Eina_Bool _clipper_del_cb(void *data, Eo *eo_clip, const 
Eo_Event_Description *desc EINA_UNUSED, void *info EINA_UNUSED);
+
 EOLIAN void
 _evas_object_clip_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object 
*eo_clip)
 {
@@ -281,6 +283,8 @@ _evas_object_clip_set(Eo *eo_obj, 
Evas_Object_Protected_Data *obj, Evas_Object *
      }
    if (obj->cur->clipper)
      {
+        Evas_Object_Protected_Data *old_clip = obj->cur->clipper;
+
        /* unclip */
         obj->cur->clipper->clip.cache_clipees_answer = 
eina_list_free(obj->cur->clipper->clip.cache_clipees_answer);
         obj->cur->clipper->clip.clipees = 
eina_list_remove(obj->cur->clipper->clip.clipees, obj);
@@ -320,10 +324,10 @@ _evas_object_clip_set(Eo *eo_obj, 
Evas_Object_Protected_Data *obj, Evas_Object *
         evas_object_change(eo_obj, obj);
 
         EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
-          {
-             state_write->clipper = NULL;
-          }
+          state_write->clipper = NULL;
         EINA_COW_STATE_WRITE_END(obj, state_write, cur);
+        if (obj->prev->clipper != old_clip)
+          eo_do(old_clip->object, eo_event_callback_del(EO_BASE_EVENT_DEL, 
_clipper_del_cb, eo_obj));
      }
 
    /* image object clipper */
@@ -350,11 +354,12 @@ _evas_object_clip_set(Eo *eo_obj, 
Evas_Object_Protected_Data *obj, Evas_Object *
                                   clip->cur->geometry.w, 
clip->cur->geometry.h);
  */
      }
+
    EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
-     {
-        state_write->clipper = clip;
-     }
+     state_write->clipper = clip;
    EINA_COW_STATE_WRITE_END(obj, state_write, cur);
+   if (obj->prev->clipper != clip)
+     eo_do(clip->object, eo_event_callback_add(EO_BASE_EVENT_DEL, 
_clipper_del_cb, eo_obj));
 
    clip->clip.cache_clipees_answer = 
eina_list_free(clip->clip.cache_clipees_answer);
    clip->clip.clipees = eina_list_append(clip->clip.clipees, obj);
@@ -401,7 +406,6 @@ EOLIAN void
 _evas_object_clip_unset(Eo *eo_obj, Evas_Object_Protected_Data *obj)
 {
    if (!obj->cur->clipper) return;
-
    evas_object_async_block(obj);
    obj->clip.cache_clipees_answer = 
eina_list_free(obj->clip.cache_clipees_answer);
 
@@ -413,6 +417,8 @@ _evas_object_clip_unset(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
      }
    if (obj->cur->clipper)
      {
+        Evas_Object_Protected_Data *old_clip = obj->cur->clipper;
+
         obj->cur->clipper->clip.clipees = 
eina_list_remove(obj->cur->clipper->clip.clipees, obj);
         if (!obj->cur->clipper->clip.clipees)
           {
@@ -445,12 +451,13 @@ _evas_object_clip_unset(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
              _evas_object_clip_mask_unset(obj->cur->clipper);
           }
        evas_object_change(obj->cur->clipper->object, obj->cur->clipper);
+
+        EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
+          state_write->clipper = NULL;
+        EINA_COW_STATE_WRITE_END(obj, state_write, cur);
+        if (obj->prev->clipper != old_clip)
+          eo_do(old_clip->object, eo_event_callback_del(EO_BASE_EVENT_DEL, 
_clipper_del_cb, eo_obj));
      }
-   EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
-     {
-        state_write->clipper = NULL;
-     }
-   EINA_COW_STATE_WRITE_END(obj, state_write, cur);
 
    evas_object_change(eo_obj, obj);
    evas_object_clip_dirty(eo_obj, obj);
@@ -470,6 +477,43 @@ _evas_object_clip_unset(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
    evas_object_clip_across_check(eo_obj, obj);
 }
 
+static Eina_Bool
+_clipper_del_cb(void *data, Eo *eo_clip, const Eo_Event_Description *desc 
EINA_UNUSED, void *info EINA_UNUSED)
+{
+   Evas_Object *eo_obj = data;
+   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, 
EVAS_OBJECT_CLASS);
+
+   if (!obj) return EO_CALLBACK_CONTINUE;
+
+   _evas_object_clip_unset(eo_obj, obj);
+   if (obj->prev->clipper && (obj->prev->clipper->object == eo_clip))
+     {
+        // not removing cb since it's the del cb... it can't be called again!
+        EINA_COW_STATE_WRITE_BEGIN(obj, state_write, prev)
+          state_write->clipper = NULL;
+        EINA_COW_STATE_WRITE_END(obj, state_write, prev);
+     }
+
+   return EO_CALLBACK_CONTINUE;
+}
+
+void
+_evas_object_clip_prev_reset(Evas_Object_Protected_Data *obj, Eina_Bool 
cur_prev)
+{
+   if (obj->prev->clipper)
+     {
+        Evas_Object_Protected_Data *clip = obj->prev->clipper;
+        if (!cur_prev)
+          {
+             EINA_COW_STATE_WRITE_BEGIN(obj->prev->clipper, state_write, prev)
+               state_write->clipper = NULL;
+             EINA_COW_STATE_WRITE_END(obj->prev->clipper, state_write, prev);
+          }
+        if (clip != obj->cur->clipper)
+          eo_do(clip->object, eo_event_callback_del(EO_BASE_EVENT_DEL, 
_clipper_del_cb, obj->object));
+     }
+}
+
 EOLIAN Eina_List *
 _evas_object_clipees_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data 
*obj)
 {
diff --git a/src/lib/evas/canvas/evas_object_main.c 
b/src/lib/evas/canvas/evas_object_main.c
index 1fd2348..9f83689 100644
--- a/src/lib/evas/canvas/evas_object_main.c
+++ b/src/lib/evas/canvas/evas_object_main.c
@@ -159,6 +159,7 @@ evas_object_cur_prev(Evas_Object *eo_obj)
           map_write->prev = map_write->cur;
         EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
      }
+   _evas_object_clip_prev_reset(obj, EINA_TRUE);
    eina_cow_memcpy(evas_object_state_cow, (const Eina_Cow_Data **) &obj->prev, 
obj->cur);
 }
 
@@ -704,13 +705,18 @@ _evas_object_eo_base_destructor(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
         goto end;
      }
    evas_object_grabs_cleanup(eo_obj, obj);
-   /* "while" should be used for null check of obj->clip.clipees,
-      because evas_objct_clip_unset can set null to obj->clip.clipees */
-   while (obj->clip.clipees)
+   if (obj->clip.clipees)
      {
-        Evas_Object_Protected_Data *tmp;
-        tmp = eina_list_data_get(obj->clip.clipees);
-        evas_object_clip_unset(tmp->object);
+        ERR("object %p still has %d clippees after del callback",
+            eo_obj, eina_list_count(obj->clip.clipees));
+        /* "while" should be used for null check of obj->clip.clipees,
+           because evas_objct_clip_unset can set null to obj->clip.clipees */
+        while (obj->clip.clipees)
+          {
+             Evas_Object_Protected_Data *tmp;
+             tmp = eina_list_data_get(obj->clip.clipees);
+             evas_object_clip_unset(tmp->object);
+          }
      }
    EINA_LIST_FOREACH_SAFE(obj->proxy->proxies, l, l2, proxy)
      {
@@ -734,6 +740,8 @@ _evas_object_eo_base_destructor(Eo *eo_obj, 
Evas_Object_Protected_Data *obj)
      }
 
    if (obj->cur->clipper) evas_object_clip_unset(eo_obj);
+   _evas_object_clip_prev_reset(obj, EINA_FALSE);
+
    evas_object_map_set(eo_obj, NULL);
    if (obj->is_smart) evas_object_smart_del(eo_obj);
    _evas_object_event_new();
diff --git a/src/lib/evas/include/evas_private.h 
b/src/lib/evas/include/evas_private.h
index b9f8a33..ac814ba 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -1650,6 +1650,7 @@ void _above_get(Eo *obj, void *_pd, va_list *list);
 void _below_get(Eo *obj, void *_pd, va_list *list);
 void _smart_move_children_relative(Eo *obj, void *_pd, va_list *list);
 void _smart_clipped_clipper_get(Eo *obj, void *_pd, va_list *list);
+void _evas_object_clip_prev_reset(Evas_Object_Protected_Data *obj, Eina_Bool 
cur_prev);
 
 void _canvas_event_default_flags_set(Eo *e, void *_pd, va_list *list);
 void _canvas_event_default_flags_get(Eo *e, void *_pd, va_list *list);

-- 


Reply via email to