summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2017-08-05 13:10:33 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2017-08-05 13:10:33 +0900
commit7b59a4851e23bb9b5b523bd50030182e1b765faa (patch)
tree4c0a68a6ab6dea5e2f030dca5757d4325a26c464
parentfb153fc57a03b1e0235ee73cc179080994542559 (diff)
downloadefl-7b59a4851e23bb9b5b523bd50030182e1b765faa.tar.gz
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
-rw-r--r--src/lib/edje/edje_callbacks.c26
-rw-r--r--src/lib/edje/edje_private.h1
-rw-r--r--src/lib/edje/edje_program.c41
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