summaryrefslogtreecommitdiff
path: root/src/bin/evas
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2014-01-13 14:21:44 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2014-01-14 14:23:04 +0900
commit6a4c84a6a48a7d02c52a1556b0ab6ded6c2de081 (patch)
tree0ad6732b45d4b5fe30b3c50c08ff007226e625bb /src/bin/evas
parent00417fe25636dc5f33b329b2f82d7d95e584e803 (diff)
downloadefl-6a4c84a6a48a7d02c52a1556b0ab6ded6c2de081.tar.gz
Evas/cserve2: Fix crash in server on file change
An inotify callback is triggered when an image file changes, and it is supposed to cleanup all references to this image. Unfortunately, it was doing it in a very unsafe way as pointers could become invalid, because of hash free callbacks in the referenced image list. Add some list safety and always assume the pointer might be dead after free operations. TBH, this _file_changed_cb function looks very confused to me (as it tries to bypass eina_hash_del).
Diffstat (limited to 'src/bin/evas')
-rw-r--r--src/bin/evas/evas_cserve2_cache.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/src/bin/evas/evas_cserve2_cache.c b/src/bin/evas/evas_cserve2_cache.c
index bc12fed505..f4ce05ed33 100644
--- a/src/bin/evas/evas_cserve2_cache.c
+++ b/src/bin/evas/evas_cserve2_cache.c
@@ -1673,26 +1673,27 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
{
File_Watch *fw = data;
File_Entry *fentry;
- Eina_List *l;
+ Eina_List *l, *l_next;
- EINA_LIST_FOREACH(fw->entries, l, fentry)
+ EINA_LIST_FOREACH_SAFE(fw->entries, l, l_next, fentry)
{
- Eina_List *ll;
+ Eina_List *ll, *ll_next;
Image_Entry *ie;
File_Data *fd;
+ int fentry_id = ENTRYID(fentry);
fentry->watcher = NULL;
- EINA_LIST_FOREACH(fentry->images, ll, ie)
+ EINA_LIST_FOREACH_SAFE(fentry->images, ll, ll_next, ie)
{
Image_Data *idata;
idata = _image_data_find(ENTRYID(ie));
- eina_hash_set(image_entries, &ENTRYID(ie), NULL);
if (ASENTRY(ie)->request /*&& !ie->base.request->processing*/)
cserve2_request_cancel_all(ASENTRY(ie)->request,
CSERVE2_FILE_CHANGED);
ASENTRY(ie)->request = NULL;
+ eina_hash_set(image_entries, &ENTRYID(ie), NULL);
if (idata)
{
@@ -1702,8 +1703,10 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
}
}
+ // from this point, fentry might have died already
+ // clean up if it's still alive somewhere
- fd = _file_data_find(ENTRYID(fentry));
+ fd = _file_data_find(fentry_id);
if (fd)
{
fd->invalid = EINA_TRUE;
@@ -1711,15 +1714,19 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
eina_hash_set(file_entries, &fd->id, NULL);
}
- if (ASENTRY(fentry)->request
- /*&& !ASENTRY(fentry)->request->processing*/)
+ fentry = (File_Entry *) eina_hash_find(file_entries, &fentry_id);
+ if (fentry)
{
- cserve2_request_cancel_all(ASENTRY(fentry)->request,
- CSERVE2_FILE_CHANGED);
- ASENTRY(fentry)->request = NULL;
+ if (ASENTRY(fentry)->request
+ /*&& !ASENTRY(fentry)->request->processing*/)
+ {
+ cserve2_request_cancel_all(ASENTRY(fentry)->request,
+ CSERVE2_FILE_CHANGED);
+ ASENTRY(fentry)->request = NULL;
+ }
+ if (!fentry->images && !ASENTRY(fentry)->references)
+ _hash_file_entry_free(fentry);
}
- if (!fentry->images && !ASENTRY(fentry)->references)
- _hash_file_entry_free(fentry);
}
eina_hash_del_by_key(file_watch, fw->path);