raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=7b59a4851e23bb9b5b523bd50030182e1b765faa

commit 7b59a4851e23bb9b5b523bd50030182e1b765faa
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Sat Aug 5 13:10:33 2017 +0900

    edje crash with run program references - fix
    
    i found a crash today where a heme could cause a crash if it just did
    the right things. the run program was freed while still being
    accessed. so add some ref counting to keep it alive until references
    go to 0. and add soem refs while we store it in lists.
    
    @fix
---
 src/lib/edje/edje_callbacks.c | 26 +++++++++++++++++++++-----
 src/lib/edje/edje_private.h   |  1 +
 src/lib/edje/edje_program.c   | 41 ++++++++++++++++++++++++++++++++++-------
 3 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/src/lib/edje/edje_callbacks.c b/src/lib/edje/edje_callbacks.c
index ac6f52c9eb..06ed0f81a7 100644
--- a/src/lib/edje/edje_callbacks.c
+++ b/src/lib/edje/edje_callbacks.c
@@ -387,35 +387,51 @@ _edje_timer_cb(void *data, const Efl_Event *event 
EINA_UNUSED)
    _edje_util_freeze(ed);
    if ((!ed->paused) && (!ed->delete_me))
      {
-        const void *tmp;
+        Edje_Running_Program *tmp;
 
         ed->walking_actions = EINA_TRUE;
         EINA_LIST_FOREACH(ed->actions, l, tmp)
-          newl = eina_list_append(newl, tmp);
+          {
+             tmp->ref++;
+             newl = eina_list_append(newl, tmp);
+          }
         while (newl)
           {
              Edje_Running_Program *runp;
 
              runp = eina_list_data_get(newl);
              newl = eina_list_remove(newl, eina_list_data_get(newl));
+             runp->ref--;
              if (!runp->delete_me)
                _edje_program_run_iterate(runp, t);
              if (_edje_block_break(ed))
                {
-                  eina_list_free(newl);
+                  EINA_LIST_FREE(newl, tmp)
+                    {
+                       tmp->ref--;
+                       if ((tmp->delete_me) && (tmp->ref == 0))
+                         {
+                            _edje_program_run_cleanup(ed, tmp);
+                            free(tmp);
+                         }
+                    }
                   newl = NULL;
                   goto break_prog;
                }
           }
         EINA_LIST_FOREACH(ed->actions, l, tmp)
-          newl = eina_list_append(newl, tmp);
+          {
+             tmp->ref++;
+             newl = eina_list_append(newl, tmp);
+          }
         while (newl)
           {
              Edje_Running_Program *runp;
 
              runp = eina_list_data_get(newl);
              newl = eina_list_remove(newl, eina_list_data_get(newl));
-             if (runp->delete_me)
+             runp->ref--;
+             if ((runp->delete_me) && (runp->ref == 0))
                {
                   _edje_program_run_cleanup(ed, runp);
                   free(runp);
diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h
index 139272066e..a4a334ccc0 100644
--- a/src/lib/edje/edje_private.h
+++ b/src/lib/edje/edje_private.h
@@ -2059,6 +2059,7 @@ struct _Edje_Running_Program
    Edje           *edje;
    Edje_Program   *program;
    double          start_time;
+   unsigned short  ref;
    Eina_Bool       delete_me : 1;
 };
 
diff --git a/src/lib/edje/edje_program.c b/src/lib/edje/edje_program.c
index 6c90f46650..4dd5fb7816 100644
--- a/src/lib/edje/edje_program.c
+++ b/src/lib/edje/edje_program.c
@@ -299,20 +299,32 @@ _edje_object_animation_set(Eo *obj, Edje *ed, Eina_Bool 
on)
    if (!on)
      {
         Eina_List *newl = NULL;
-        const void *data;
+        Edje_Running_Program *data;
 
         EINA_LIST_FOREACH(ed->actions, l, data)
-          newl = eina_list_append(newl, data);
+          {
+             data->ref++;
+             newl = eina_list_append(newl, data);
+          }
         while (newl)
           {
              Edje_Running_Program *runp;
 
              runp = eina_list_data_get(newl);
              newl = eina_list_remove(newl, eina_list_data_get(newl));
+             runp->ref--;
              _edje_program_run_iterate(runp, runp->start_time + 
TO_DOUBLE(runp->program->tween.time));
              if (_edje_block_break(ed))
                {
-                  eina_list_free(newl);
+                 EINA_LIST_FREE(newl, data)
+                    {
+                       data->ref--;
+                       if ((data->delete_me) && (data->ref == 0))
+                         {
+                            _edje_program_run_cleanup(ed, data);
+                            free(data);
+                         }
+                    }
                   goto break_prog;
                }
           }
@@ -434,7 +446,14 @@ _edje_program_run_iterate(Edje_Running_Program *runp, 
double tim)
         //     _edje_emit(ed, "program,stop", runp->program->name);
         if (_edje_block_break(ed))
           {
-             if (!ed->walking_actions) free(runp);
+             if (!ed->walking_actions)
+               {
+                  if (runp->ref == 0)
+                    {
+                       _edje_program_run_cleanup(ed, runp);
+                       free(runp);
+                    }
+               }
              goto break_prog;
           }
         EINA_LIST_FOREACH(runp->program->after, l, pa)
@@ -447,14 +466,22 @@ _edje_program_run_iterate(Edje_Running_Program *runp, 
double tim)
                   if (pr) _edje_program_run(ed, pr, 0, "", "");
                   if (_edje_block_break(ed))
                     {
-                       if (!ed->walking_actions) free(runp);
+                       if ((!ed->walking_actions) && (runp->ref == 0))
+                         {
+                            _edje_program_run_cleanup(ed, runp);
+                            free(runp);
+                         }
                        goto break_prog;
                     }
                }
           }
         _edje_util_thaw(ed);
         _edje_unref(ed);
-        if (!ed->walking_actions) free(runp);
+        if ((!ed->walking_actions) && (runp->ref == 0))
+          {
+             _edje_program_run_cleanup(ed, runp);
+             free(runp);
+          }
         _edje_unblock(ed);
         return EINA_FALSE;
      }
@@ -513,7 +540,7 @@ _edje_program_end(Edje *ed, Edje_Running_Program *runp)
    //   _edje_emit(ed, "program,stop", pname);
    _edje_util_thaw(ed);
    _edje_unref(ed);
-   if (free_runp) free(runp);
+   if ((free_runp) && (runp->ref == 0)) free(runp);
 }
 
 #ifdef HAVE_EPHYSICS

-- 


Reply via email to