diff options
author | Carsten Haitzler (Rasterman) <raster@rasterman.com> | 2017-08-05 13:10:33 +0900 |
---|---|---|
committer | Carsten Haitzler (Rasterman) <raster@rasterman.com> | 2017-08-05 13:10:33 +0900 |
commit | 7b59a4851e23bb9b5b523bd50030182e1b765faa (patch) | |
tree | 4c0a68a6ab6dea5e2f030dca5757d4325a26c464 | |
parent | fb153fc57a03b1e0235ee73cc179080994542559 (diff) | |
download | efl-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.c | 26 | ||||
-rw-r--r-- | src/lib/edje/edje_private.h | 1 | ||||
-rw-r--r-- | 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 |