diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2003-07-05 22:59:35 +0400 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2003-07-05 22:59:35 +0400 |
commit | f2d3c47b14afcfc782e8e8ce88e2ab624e87b264 (patch) | |
tree | 58e33f7e7127a1d75c83225124c23140f3fc70b6 /winsup/cygwin/mmap.cc | |
parent | 4b2cbaeefd38dc562dc4ee362033ee2edad06659 (diff) |
* 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.
Diffstat (limited to 'winsup/cygwin/mmap.cc')
-rw-r--r-- | winsup/cygwin/mmap.cc | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index cd974bed1..00ef3e6bc 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -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. */ |