Eio monitor: Fix crash on invalid data access
authorJean-Philippe Andre <jp.andre@samsung.com>
Tue, 14 Jan 2014 04:33:16 +0000 (13:33 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Tue, 14 Jan 2014 05:23:05 +0000 (14:23 +0900)
Fix race condition when touching/changing a (theme) file often.
An Eio_Monitor was marked as "delete_me" but the rename callback
was still called, leading to memory access to already freed
objects.

Test protocol was:
ELM_THEME=~/default.edj elementary_test &
watch touch ~/default.edj

src/lib/eio/eio_monitor.c
src/lib/eio/eio_monitor_inotify.c

index 53581a4..bc6c2d8 100644 (file)
@@ -37,7 +37,11 @@ _eio_monitor_free(Eio_Monitor *monitor)
    if (!monitor->delete_me)
      eina_hash_del(_eio_monitors, monitor->path, monitor);
 
-   if (monitor->exist) eio_file_cancel(monitor->exist);
+   if (monitor->exist)
+     {
+        eio_file_cancel(monitor->exist);
+        monitor->exist = NULL;
+     }
 
    if (monitor->backend)
      {
@@ -185,6 +189,9 @@ _eio_monitor_send(Eio_Monitor *monitor, const char *filename, int event_code)
 {
    Eio_Monitor_Event *ev;
 
+   if (monitor->delete_me)
+     return;
+
    ev = calloc(1, sizeof (Eio_Monitor_Event));
    if (!ev) return;
 
@@ -200,6 +207,9 @@ _eio_monitor_rename(Eio_Monitor *monitor, const char *newpath)
 {
   const char *tmp;
 
+  if (monitor->delete_me)
+    return;
+
   /* destroy old state */
   if (monitor->exist)
     {
index 0826845..fbfc24e 100644 (file)
@@ -92,6 +92,9 @@ _eio_inotify_events(Eio_Monitor_Backend *backend, const char *file, int mask)
    unsigned int i;
    Eina_Bool is_dir;
 
+   if (backend->parent->delete_me)
+     return;
+
    length = file ? strlen(file) : 0;
    tmp_length = eina_stringshare_strlen(backend->parent->path) + length + 2;
    tmp = alloca(sizeof (char) * tmp_length);
@@ -255,13 +258,16 @@ void eio_monitor_backend_add(Eio_Monitor *monitor)
 
 void eio_monitor_backend_del(Eio_Monitor *monitor)
 {
+   Eio_Monitor_Backend *backend;
+
    if (!_inotify_fdh)
      eio_monitor_fallback_del(monitor);
 
-   if (!monitor->backend) return;
-
-   eina_hash_del(_inotify_monitors, &monitor->backend->hwnd, monitor->backend);
+   backend = monitor->backend;
    monitor->backend = NULL;
+   if (!backend) return;
+
+   eina_hash_del(_inotify_monitors, &backend->hwnd, backend);
 }