eina: fix a possible race condition during eina_file_close.
authorJérémy Zurcher <jeremy@asynk.ch>
Wed, 20 Nov 2013 09:19:16 +0000 (10:19 +0100)
committerJérémy Zurcher <jeremy@asynk.ch>
Wed, 20 Nov 2013 09:22:00 +0000 (10:22 +0100)
replay 7e8fb93 without the breakage

ChangeLog
NEWS
src/lib/eina/eina_file_common.c
src/tests/eina/eina_test_file.c

index 3dc7c28..6c3dea3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-11-20  Cedric Bail
+
+       * Eina: Fix a possible race condition during eina_file_close.
+
 2013-11-19  Tom Hacohen
 
        * Evas textblock: Fixed order of tags inserted with markup_app/prepend.
diff --git a/NEWS b/NEWS
index 6a1f8bd..5ce9bcf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -268,7 +268,8 @@ Fixes:
      - Fix memory leak in eina_xattr_value_ls.
      - Fix magic failure in eina_value_array_count when array has not been allocated.
      - Fix issue when wchar_t is signed and eina_unicode does negative array lookups.
-     - Eina: fix eina_file_map_lines() to not drop of one character in the last line.
+     - Fix eina_file_map_lines() to not drop of one character in the last line.
+     - Fix a possible race condition during eina_file_close().
     * Eet:
      - Fix PPC (big endian) image codec bug.
      - Fix leak in eet_pbkdf2_sha1 with OpenSSL.
index 7b05b3b..7f83c87 100644 (file)
@@ -451,17 +451,20 @@ eina_file_close(Eina_File *file)
 
    EINA_SAFETY_ON_NULL_RETURN(file);
 
+   eina_lock_take(&_eina_file_lock_cache);
+
    eina_lock_take(&file->lock);
    file->refcount--;
    if (file->refcount == 0) leave = EINA_FALSE;
    eina_lock_release(&file->lock);
-   if (leave) return;
-
-   eina_lock_take(&_eina_file_lock_cache);
+   if (leave) goto end;
 
    eina_hash_del(_eina_file_cache, file->filename, file);
+
+   // Backend specific file resource close
    eina_file_real_close(file);
 
+ end:
    eina_lock_release(&_eina_file_lock_cache);
 }
 
index f2f3225..e8f735d 100644 (file)
@@ -441,6 +441,39 @@ START_TEST(eina_test_file_virtualize)
 }
 END_TEST
 
+static void *
+_eina_test_file_thread(void *data EINA_UNUSED, Eina_Thread t EINA_UNUSED)
+{
+   Eina_File *f;
+   unsigned int i;
+
+   for (i = 0; i < 10000; ++i)
+     {
+        f = eina_file_open("/bin/sh", EINA_FALSE);
+        fail_if(!f);
+        eina_file_close(f);
+     }
+
+   return NULL;
+}
+
+START_TEST(eina_test_file_thread)
+{
+   Eina_Thread th[4];
+   unsigned int i;
+
+   fail_if(!eina_init());
+
+   for (i = 0; i < 4; i++)
+     fail_if(!(eina_thread_create(&th[i], EINA_THREAD_NORMAL, 0, _eina_test_file_thread, NULL)));
+
+   for (i = 0; i < 4; i++)
+     fail_if(eina_thread_join(th[i]) != NULL);
+
+   eina_shutdown();
+}
+END_TEST
+
 void
 eina_test_file(TCase *tc)
 {
@@ -449,5 +482,6 @@ eina_test_file(TCase *tc)
    tcase_add_test(tc, eina_file_ls_simple);
    tcase_add_test(tc, eina_file_map_new_test);
    tcase_add_test(tc, eina_test_file_virtualize);
+   tcase_add_test(tc, eina_test_file_thread);
 }