OSDN Git Service

* mmap.cc (list::match): Add parameters to return valid address and
authorcorinna <corinna>
Sat, 5 Jul 2003 18:59:35 +0000 (18:59 +0000)
committercorinna <corinna>
Sat, 5 Jul 2003 18:59:35 +0000 (18:59 +0000)
length back to munmap().  Evaluate intersection between given
area and mapped area and return it, if any.
(mmap64): On regular files, don't allow mappings beginning beyond
EOF.  Return with errno set to ENXIO instead.
(munmap): Rewrite SUSv3 conformant.  Check if given memory area is
valid.  Unmap all maps inside given memory area.  Don't return error
if no mapping has been unmapped.

winsup/cygwin/ChangeLog
winsup/cygwin/mmap.cc

index fd982fa..0bc113e 100644 (file)
@@ -1,4 +1,15 @@
-2003-07-04  N Stephens  <nigel@mips.com>
+2003-07-05  Corinna Vinschen  <corinna@vinschen.de>
+
+       * mmap.cc (list::match): Add parameters to return valid address and
+       length back to munmap().  Evaluate intersection between given
+       area and mapped area and return it, if any.
+       (mmap64): On regular files, don't allow mappings beginning beyond
+       EOF.  Return with errno set to ENXIO instead.
+       (munmap): Rewrite SUSv3 conformant.  Check if given memory area is
+       valid.  Unmap all maps inside given memory area.  Don't return error
+       if no mapping has been unmapped.
+
+2003-07-05  N Stephens  <nigel@mips.com>
 
        * fhandler.h (fhandler_socket::get_connect_state): New method to
        return socket connection state.
index cd974be..00ef3e6 100644 (file)
@@ -270,7 +270,8 @@ public:
   void erase (int i);
   void erase ();
   mmap_record *match (_off64_t off, DWORD len);
-  long match (caddr_t addr, DWORD len, long start);
+  long match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len,
+             long start);
 };
 
 list::list ()
@@ -323,13 +324,24 @@ list::match (_off64_t off, DWORD len)
 
 /* Used in munmap() */
 long
-list::match (caddr_t addr, DWORD len, _off_t start)
+list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len,
+            _off_t start)
 {
+  caddr_t low, high;
+
   for (int i = start + 1; i < nrecs; ++i)
-    if (addr >= recs[i].get_address ()
-       && addr + len <= recs[i].get_address ()
-                        + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()))
-      return i;
+    {
+      low = (addr >= recs[i].get_address ()) ? addr : recs[i].get_address ();
+      high = recs[i].get_address () 
+            + (PAGE_CNT (recs[i].get_size ()) * getpagesize ());
+      high = (addr + len < high) ? addr + len : high;
+      if (low < high)
+       {
+         m_addr = low;
+         m_len = high - low;
+         return i;
+       }
+    }
   return -1;
 }
 
@@ -486,6 +498,16 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
          DWORD high;
          DWORD low = GetFileSize (fh->get_handle (), &high);
          _off64_t fsiz = ((_off64_t)high << 32) + low;
+         /* Don't allow mappings beginning beyond EOF since Windows can't
+            handle that POSIX like.  FIXME: Still looking for a good idea
+            to allow that nevertheless. */
+         if (gran_off >= fsiz)
+           {
+             set_errno (ENXIO);
+             ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK,
+                                  "mmap");
+             return MAP_FAILED;
+           }
          fsiz -= gran_off;
          if (gran_len > fsiz)
            gran_len = fsiz;
@@ -591,16 +613,16 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, _off_t off)
   return mmap64 (addr, len, prot, flags, fd, (_off64_t)off);
 }
 
-/* munmap () removes an mmapped area.  It insists that base area
-   requested is the same as that mmapped, error if not. */
+/* munmap () removes all mmapped pages between addr and addr+len. */
 
 extern "C" int
 munmap (caddr_t addr, size_t len)
 {
   syscall_printf ("munmap (addr %x, len %d)", addr, len);
 
-  /* Error conditions according to SUSv2 */
-  if (((DWORD)addr % getpagesize ()) || !len)
+  /* Error conditions according to SUSv3 */
+  if (!addr || ((DWORD)addr % getpagesize ()) || !len
+      || IsBadReadPtr (addr, len))
     {
       set_errno (EINVAL);
       syscall_printf ("-1 = munmap(): Invalid parameters");
@@ -608,17 +630,15 @@ munmap (caddr_t addr, size_t len)
     }
 
   SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
-  /* Check if a mmap'ed area was ever created */
   if (mmapped_areas == NULL)
     {
       syscall_printf ("-1 = munmap(): mmapped_areas == NULL");
-      set_errno (EINVAL);
       ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
-      return -1;
+      return 0;
     }
 
-  /* Iterate through the map, looking for the mmapped area.
-     Error if not found. */
+  /* Iterate through the map, unmap pages between addr and addr+len
+     in all maps. */
 
   for (int it = 0; it < mmapped_areas->nlists; ++it)
     {
@@ -626,10 +646,13 @@ munmap (caddr_t addr, size_t len)
       if (map_list)
        {
          long li = -1;
-         if ((li = map_list->match(addr, len, li)) >= 0)
+         caddr_t u_addr;
+         DWORD u_len;
+
+         while ((li = map_list->match(addr, len, u_addr, u_len, li)) >= 0)
            {
              mmap_record *rec = map_list->recs + li;
-             if (rec->unmap_map (addr, len))
+             if (rec->unmap_map (u_addr, u_len))
                {
                  fhandler_base *fh = rec->alloc_fh ();
                  fh->munmap (rec->get_handle (), addr, len);
@@ -638,18 +661,13 @@ munmap (caddr_t addr, size_t len)
                  /* Delete the entry. */
                  map_list->erase (li);
                }
-             syscall_printf ("0 = munmap(): %x", addr);
-             ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
-             return 0;
            }
        }
     }
 
-  set_errno (EINVAL);
-  syscall_printf ("-1 = munmap(): EINVAL");
-
   ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap");
-  return -1;
+  syscall_printf ("0 = munmap(): %x", addr);
+  return 0;
 }
 
 /* Sync file with memory. Ignore flags for now. */