Windows: fix eina_file_map_new()
authorVincent Torri <vincent.torri@gmail.com>
Thu, 25 Jun 2020 14:44:15 +0000 (14:44 +0000)
committerJongmin Lee <jm105.lee@samsung.com>
Sun, 28 Jun 2020 22:34:20 +0000 (07:34 +0900)
the offset passed to MapViewOfFile() must be a multiple of the granularity.

https://docs.microsoft.com/en-us/windows/win32/memory/creating-a-view-within-a-file is taken as basis for this patch

Reviewed-by: Stefan Schmidt <stefan@datenfreihafen.org>
Reviewed-by: Wander Lairson Costa <wander.lairson@gmail.com>
Differential Revision: https://phab.enlightenment.org/D12031

src/lib/eina/eina_file_common.h
src/lib/eina/eina_file_win32.c

index 9aedfae..16fb772 100644 (file)
@@ -124,6 +124,9 @@ struct _Eina_File_Map
 
    Eina_Bool hugetlb : 1;  /**< Indicates if we are using HugeTLB */
    Eina_Bool faulty : 1;   /**< Indicates if this region was not mapped correctly (i.e. the call to mmap(2) failed). */
+#ifdef _WIN32
+   void *ret;  /**< A pointer to the mapped region */
+#endif
 };
 
 /**
index ca8e78b..46449fd 100644 (file)
@@ -900,7 +900,7 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
    if (offset + length > file->length)
      return NULL;
 
-   if (offset == 0 && length == file->length)
+   if (offset == 0UL && length == file->length)
      return eina_file_map_all(file, rule);
 
    if (file->virtual)
@@ -914,40 +914,56 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
    map = eina_hash_find(file->map, &key);
    if (!map)
      {
+        SYSTEM_INFO si;
         HANDLE fm;
+        __int64 map_size;
+        DWORD view_offset;
+        DWORD view_length;
+        DWORD granularity;
+
         map = malloc(sizeof (Eina_File_Map));
         if (!map)
-          {
-             eina_lock_release(&file->lock);
-             return NULL;
-          }
+          goto on_error;
 
-        /* the length parameter is unsigned long, that is a DWORD */
-        /* so the max size high parameter of CreateFileMapping is 0 */
+        /*
+         * the size of the mapping object is the offset plus the length,
+         * which might be greater than a DWORD
+         */
+        map_size = (__int64)offset + (__int64)length;
         fm = CreateFileMapping(file->handle, NULL, PAGE_READONLY,
-                                     0, (DWORD)length, NULL);
+                               (DWORD)((map_size >> 32) & 0x00000000ffffffffULL),
+                               (DWORD)(map_size & 0x00000000ffffffffULL),
+                               NULL);
         if (!fm)
-          return NULL;
-
+          goto on_error;
+
+        /*
+         * get the system allocation granularity as the
+         * offset passed to MapViewOfFile() must be a
+         * multiple of this granularity
+         */
+        GetSystemInfo(&si);
+        granularity = si.dwAllocationGranularity;
+
+        /*
+         * view_offset is the greatest multiple of granularity, less or equal
+         * than offset (and can be stored in a DWORD)
+         */
+        view_offset = (offset / granularity) * granularity;
+        view_length = (offset - view_offset) + length;
         map->map = MapViewOfFile(fm, FILE_MAP_READ,
-                             offset & 0xffff0000,
-                             offset & 0x0000ffff,
-                             length);
+                                 0,
+                                 view_offset,
+                                 view_length);
         CloseHandle(fm);
         if (!map->map)
-          map->map = MAP_FAILED;
+          goto on_error;
 
+        map->ret = (unsigned char *)map->map + (offset - view_offset);
         map->offset = offset;
         map->length = length;
         map->refcount = 0;
 
-        if (map->map == MAP_FAILED)
-          {
-             free(map);
-             eina_lock_release(&file->lock);
-             return NULL;
-          }
-
         eina_hash_add(file->map, &key, map);
         eina_hash_direct_add(file->rmap, map->map, map);
      }
@@ -956,7 +972,13 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
 
    eina_lock_release(&file->lock);
 
-   return map->map;
+   return map->ret;
+
+ on_error:
+   free(map);
+   eina_lock_release(&file->lock);
+
+   return NULL;
 }
 
 EAPI void