Use mprotect instead of mmap in GC_unmap() on Cygwin
authorErik M. Bray <erik.bray@lri.fr>
Tue, 17 Oct 2017 08:50:03 +0000 (11:50 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 17 Oct 2017 08:50:03 +0000 (11:50 +0300)
Issue #187 (BDWGC).

* configure.ac [$enable_munmap!="" && $enable_munmap!=no]
(USE_WINALLOC): Replace AC_DEFINE with AH_TEMPLATE; remove comment
about a workaround for Cygwin; remove "if $host=*-*-cygwin*".
* os_dep.c [CYGWIN32 && USE_MUNMAP] (GC_setpagesize): Set GC_page_size
to dwAllocationGranularity (instead of dwPageSize); add comment; add
assertion that dwAllocationGranularity is not less than dwPageSize.
* os_dep.c [USE_MUNMAP && CYGWIN32 && !USE_WINALLOC] (GC_unmap,
GC_unmap_gap): Call mprotect() instead of mmap(); add comment.

configure.ac
os_dep.c

index cb314a6..c379695 100644 (file)
@@ -887,14 +887,9 @@ AC_ARG_ENABLE(munmap,
 if test x$enable_munmap != x -a x$enable_munmap != xno; then
     AC_DEFINE([USE_MMAP], 1,
               [Define to use mmap instead of sbrk to expand the heap.])
-    case "$host" in
-      *-*-cygwin*)
-        # Workaround for Cygwin: use VirtualAlloc since mmap(PROT_NONE) fails
-        AC_DEFINE([USE_WINALLOC], 1,
+    AH_TEMPLATE([USE_WINALLOC],
                   [Define to use Win32 VirtualAlloc (instead of sbrk or
                    mmap) to expand the heap.])
-        ;;
-    esac
     AC_DEFINE([USE_MUNMAP], 1,
               [Define to return memory to OS with munmap calls
                (see doc/README.macros).])
index 6b009fc..2ca6f0a 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -713,7 +713,20 @@ GC_INNER size_t GC_page_size = 0;
   GC_INNER void GC_setpagesize(void)
   {
     GetSystemInfo(&GC_sysinfo);
-    GC_page_size = (size_t)GC_sysinfo.dwPageSize;
+#   if defined(CYGWIN32) && defined(USE_MUNMAP)
+      /* Allocations made with mmap() are aligned to the allocation     */
+      /* granularity, which (at least on 64-bit Windows OS) is not the  */
+      /* same as the page size.  Probably a separate variable could     */
+      /* be added to distinguish the allocation granularity from the    */
+      /* actual page size, but in practice there is no good reason to   */
+      /* make allocations smaller than dwAllocationGranularity, so we   */
+      /* just use it instead of the actual page size here (as Cygwin    */
+      /* itself does in many cases).                                    */
+      GC_page_size = (size_t)GC_sysinfo.dwAllocationGranularity;
+      GC_ASSERT(GC_page_size >= (size_t)GC_sysinfo.dwPageSize);
+#   else
+      GC_page_size = (size_t)GC_sysinfo.dwPageSize;
+#   endif
 #   if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
       {
         OSVERSIONINFO verInfo;
@@ -2481,17 +2494,25 @@ GC_INNER void GC_unmap(ptr_t start, size_t bytes)
       /* We immediately remap it to prevent an intervening mmap from    */
       /* accidentally grabbing the same address space.                  */
       {
-        void * result;
-
-        result = mmap(start_addr, len, PROT_NONE,
-                      MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
-                      zero_fd, 0/* offset */);
-        if (result != (void *)start_addr)
-          ABORT("mmap(PROT_NONE) failed");
-#       if defined(CPPCHECK) || defined(LINT2)
-          /* Explicitly store the resource handle to a global variable. */
-          GC_noop1((word)result);
-#       endif
+#       ifdef CYGWIN32
+          /* Calling mmap() with the new protection flags on an         */
+          /* existing memory map with MAP_FIXED is broken on Cygwin.    */
+          /* However, calling mprotect() on the given address range     */
+          /* with PROT_NONE seems to work fine.                         */
+          if (mprotect(start_addr, len, PROT_NONE))
+            ABORT("mprotect(PROT_NONE) failed");
+#       else
+          void * result = mmap(start_addr, len, PROT_NONE,
+                               MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
+                               zero_fd, 0/* offset */);
+
+          if (result != (void *)start_addr)
+            ABORT("mmap(PROT_NONE) failed");
+#         if defined(CPPCHECK) || defined(LINT2)
+            /* Explicitly store the resource handle to a global variable. */
+            GC_noop1((word)result);
+#         endif
+#       endif /* !CYGWIN32 */
       }
       GC_unmapped_bytes += len;
 #   endif
@@ -2598,15 +2619,20 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
 #   else
       if (len != 0) {
         /* Immediately remap as above. */
-        void * result;
-        result = mmap(start_addr, len, PROT_NONE,
-                      MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
-                      zero_fd, 0/* offset */);
-        if (result != (void *)start_addr)
-          ABORT("mmap(PROT_NONE) failed");
-#       if defined(CPPCHECK) || defined(LINT2)
-          GC_noop1((word)result);
-#       endif
+#       ifdef CYGWIN32
+          if (mprotect(start_addr, len, PROT_NONE))
+            ABORT("mprotect(PROT_NONE) failed");
+#       else
+          void * result = mmap(start_addr, len, PROT_NONE,
+                               MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
+                               zero_fd, 0/* offset */);
+
+          if (result != (void *)start_addr)
+            ABORT("mmap(PROT_NONE) failed");
+#         if defined(CPPCHECK) || defined(LINT2)
+            GC_noop1((word)result);
+#         endif
+#       endif /* !CYGWIN32 */
         GC_unmapped_bytes += len;
       }
 #   endif