summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCedric Bail <cedric.bail@samsung.com>2013-11-20 13:02:37 +0900
committerCedric Bail <cedric.bail@samsung.com>2013-11-20 13:02:37 +0900
commit7e8fb93206ee95945bb757267832537c13ab4287 (patch)
tree8ff6ef8d854f28ac0dbcb1ebc86d7df076c03ccf /src
parent0146e3dacc87189eba100bf5489498290ec9f86b (diff)
eina: fix a possible race condition during eina_file_close.
The lock on the main hash was taken to late (after we took the decision to remove the targeted Eina_File from the cache), this means it was possible to get an Eina_File from the cache that was going to be removed. This patch attempt to fix that potential race condition. Hopefully should fix T461.
Diffstat (limited to 'src')
-rw-r--r--src/lib/eina/eina_file.c9
-rw-r--r--src/lib/eina/eina_file_common.c15
-rw-r--r--src/lib/eina/eina_file_common.h3
-rw-r--r--src/lib/eina/eina_file_win32.c7
-rw-r--r--src/tests/eina/eina_test_file.c34
5 files changed, 53 insertions, 15 deletions
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index 6d7ee56f54..8ae5a0f4ed 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -305,11 +305,6 @@ eina_file_real_close(Eina_File *file)
305{ 305{
306 Eina_File_Map *map; 306 Eina_File_Map *map;
307 307
308 if (file->refcount != 0) return;
309
310 eina_hash_free(file->rmap);
311 eina_hash_free(file->map);
312
313 EINA_LIST_FREE(file->dead_map, map) 308 EINA_LIST_FREE(file->dead_map, map)
314 { 309 {
315 munmap(map->map, map->length); 310 munmap(map->map, map->length);
@@ -320,8 +315,6 @@ eina_file_real_close(Eina_File *file)
320 munmap(file->global_map, file->length); 315 munmap(file->global_map, file->length);
321 316
322 if (file->fd != -1) close(file->fd); 317 if (file->fd != -1) close(file->fd);
323
324 free(file);
325} 318}
326 319
327static void 320static void
@@ -912,6 +905,8 @@ eina_file_open(const char *path, Eina_Bool shared)
912 n->shared = shared; 905 n->shared = shared;
913 eina_lock_new(&n->lock); 906 eina_lock_new(&n->lock);
914 eina_hash_direct_add(_eina_file_cache, n->filename, n); 907 eina_hash_direct_add(_eina_file_cache, n->filename, n);
908
909 EINA_MAGIC_SET(n, EINA_FILE_MAGIC);
915 } 910 }
916 else 911 else
917 { 912 {
diff --git a/src/lib/eina/eina_file_common.c b/src/lib/eina/eina_file_common.c
index 7b05b3b249..f5724d70bf 100644
--- a/src/lib/eina/eina_file_common.c
+++ b/src/lib/eina/eina_file_common.c
@@ -451,17 +451,26 @@ eina_file_close(Eina_File *file)
451 451
452 EINA_SAFETY_ON_NULL_RETURN(file); 452 EINA_SAFETY_ON_NULL_RETURN(file);
453 453
454 eina_lock_take(&_eina_file_lock_cache);
455
454 eina_lock_take(&file->lock); 456 eina_lock_take(&file->lock);
455 file->refcount--; 457 file->refcount--;
456 if (file->refcount == 0) leave = EINA_FALSE; 458 if (file->refcount == 0) leave = EINA_FALSE;
457 eina_lock_release(&file->lock); 459 eina_lock_release(&file->lock);
458 if (leave) return; 460 if (leave) goto end;
459
460 eina_lock_take(&_eina_file_lock_cache);
461 461
462 eina_hash_del(_eina_file_cache, file->filename, file); 462 eina_hash_del(_eina_file_cache, file->filename, file);
463
464 // Backend specific file resource close
463 eina_file_real_close(file); 465 eina_file_real_close(file);
464 466
467 // Generic destruction of the file
468 eina_hash_free(file->rmap); file->rmap = NULL;
469 eina_hash_free(file->map); file->map = NULL;
470 EINA_MAGIC_SET(file, 0);
471 free(file);
472
473 end:
465 eina_lock_release(&_eina_file_lock_cache); 474 eina_lock_release(&_eina_file_lock_cache);
466} 475}
467 476
diff --git a/src/lib/eina/eina_file_common.h b/src/lib/eina/eina_file_common.h
index 0ac704d028..e3ee0fc553 100644
--- a/src/lib/eina/eina_file_common.h
+++ b/src/lib/eina/eina_file_common.h
@@ -24,11 +24,14 @@
24#include "eina_lock.h" 24#include "eina_lock.h"
25#include "eina_list.h" 25#include "eina_list.h"
26 26
27#define EINA_FILE_MAGIC 0xFEEDBEEF
28
27typedef struct _Eina_File_Map Eina_File_Map; 29typedef struct _Eina_File_Map Eina_File_Map;
28typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator; 30typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator;
29 31
30struct _Eina_File 32struct _Eina_File
31{ 33{
34 EINA_MAGIC;
32 const char *filename; 35 const char *filename;
33 36
34 Eina_Hash *map; 37 Eina_Hash *map;
diff --git a/src/lib/eina/eina_file_win32.c b/src/lib/eina/eina_file_win32.c
index cddf2da81a..8290501869 100644
--- a/src/lib/eina/eina_file_win32.c
+++ b/src/lib/eina/eina_file_win32.c
@@ -366,9 +366,6 @@ eina_file_real_close(Eina_File *file)
366{ 366{
367 Eina_File_Map *map; 367 Eina_File_Map *map;
368 368
369 eina_hash_free(file->rmap);
370 eina_hash_free(file->map);
371
372 EINA_LIST_FREE(file->dead_map, map) 369 EINA_LIST_FREE(file->dead_map, map)
373 { 370 {
374 UnmapViewOfFile(map->map); 371 UnmapViewOfFile(map->map);
@@ -380,8 +377,6 @@ eina_file_real_close(Eina_File *file)
380 377
381 if (file->fm) CloseHandle(file->fm); 378 if (file->fm) CloseHandle(file->fm);
382 if (file->handle) CloseHandle(file->handle); 379 if (file->handle) CloseHandle(file->handle);
383
384 free(file);
385} 380}
386 381
387static void 382static void
@@ -837,6 +832,8 @@ eina_file_open(const char *path, Eina_Bool shared)
837 n->shared = shared; 832 n->shared = shared;
838 eina_lock_new(&n->lock); 833 eina_lock_new(&n->lock);
839 eina_hash_direct_add(_eina_file_cache, n->filename, n); 834 eina_hash_direct_add(_eina_file_cache, n->filename, n);
835
836 EINA_MAGIC_SET(n, EINA_FILE_MAGIC);
840 } 837 }
841 else 838 else
842 { 839 {
diff --git a/src/tests/eina/eina_test_file.c b/src/tests/eina/eina_test_file.c
index f2f322550f..e8f735d3f0 100644
--- a/src/tests/eina/eina_test_file.c
+++ b/src/tests/eina/eina_test_file.c
@@ -441,6 +441,39 @@ START_TEST(eina_test_file_virtualize)
441} 441}
442END_TEST 442END_TEST
443 443
444static void *
445_eina_test_file_thread(void *data EINA_UNUSED, Eina_Thread t EINA_UNUSED)
446{
447 Eina_File *f;
448 unsigned int i;
449
450 for (i = 0; i < 10000; ++i)
451 {
452 f = eina_file_open("/bin/sh", EINA_FALSE);
453 fail_if(!f);
454 eina_file_close(f);
455 }
456
457 return NULL;
458}
459
460START_TEST(eina_test_file_thread)
461{
462 Eina_Thread th[4];
463 unsigned int i;
464
465 fail_if(!eina_init());
466
467 for (i = 0; i < 4; i++)
468 fail_if(!(eina_thread_create(&th[i], EINA_THREAD_NORMAL, 0, _eina_test_file_thread, NULL)));
469
470 for (i = 0; i < 4; i++)
471 fail_if(eina_thread_join(th[i]) != NULL);
472
473 eina_shutdown();
474}
475END_TEST
476
444void 477void
445eina_test_file(TCase *tc) 478eina_test_file(TCase *tc)
446{ 479{
@@ -449,5 +482,6 @@ eina_test_file(TCase *tc)
449 tcase_add_test(tc, eina_file_ls_simple); 482 tcase_add_test(tc, eina_file_ls_simple);
450 tcase_add_test(tc, eina_file_map_new_test); 483 tcase_add_test(tc, eina_file_map_new_test);
451 tcase_add_test(tc, eina_test_file_virtualize); 484 tcase_add_test(tc, eina_test_file_virtualize);
485 tcase_add_test(tc, eina_test_file_thread);
452} 486}
453 487