Cygwin: mmap: Remove AT_ROUND_TO_PAGE workaround

It's working on 32 bit OSes only anyway. It even fails on WOW64.

Drop unsupported NtMapViewOfSection flags.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2020-07-20 20:55:43 +02:00
parent eeb2dc1537
commit 1c803a6d88
2 changed files with 42 additions and 105 deletions

View File

@ -172,8 +172,7 @@ CreateMapping (HANDLE fhdl, size_t len, off_t off, DWORD openflags,
} }
else else
{ {
/* Zero len creates mapping for whole file and allows /* Zero len creates mapping for whole file */
AT_EXTENDABLE_FILE mapping, if we ever use it... */
sectionsize.QuadPart = 0; sectionsize.QuadPart = 0;
status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize, status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize,
protect, attributes, fhdl); protect, attributes, fhdl);
@ -195,12 +194,7 @@ MapView (HANDLE h, void *addr, size_t len, DWORD openflags,
DWORD protect = gen_create_protect (openflags, flags); DWORD protect = gen_create_protect (openflags, flags);
void *base = addr; void *base = addr;
SIZE_T viewsize = len; SIZE_T viewsize = len;
#ifdef __x86_64__ /* AT_ROUND_TO_PAGE isn't supported on 64 bit systems. */
ULONG alloc_type = MEM_TOP_DOWN; ULONG alloc_type = MEM_TOP_DOWN;
#else
ULONG alloc_type = (base && !wincap.is_wow64 () ? AT_ROUND_TO_PAGE : 0)
| MEM_TOP_DOWN;
#endif
#ifdef __x86_64__ #ifdef __x86_64__
/* Don't call NtMapViewOfSectionEx during fork. It requires autoloading /* Don't call NtMapViewOfSectionEx during fork. It requires autoloading
@ -878,6 +872,10 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
if (!anonymous (flags) && fd != -1) if (!anonymous (flags) && fd != -1)
{ {
UNICODE_STRING fname;
IO_STATUS_BLOCK io;
FILE_STANDARD_INFORMATION fsi;
/* Ensure that fd is open */ /* Ensure that fd is open */
cygheap_fdget cfd (fd); cygheap_fdget cfd (fd);
if (cfd < 0) if (cfd < 0)
@ -896,19 +894,16 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
/* The autoconf mmap test maps a file of size 1 byte. It then tests /* The autoconf mmap test maps a file of size 1 byte. It then tests
every byte of the entire mapped page of 64K for 0-bytes since that's every byte of the entire mapped page of 64K for 0-bytes since that's
what POSIX requires. The problem is, we can't create that mapping on what POSIX requires. The problem is, we can't create that mapping.
64 bit systems. The file mapping will be only a single page, 4K, and The file mapping will be only a single page, 4K, and the remainder
since 64 bit systems don't support the AT_ROUND_TO_PAGE flag, the of the 64K slot will result in a SEGV when accessed.
remainder of the 64K slot will result in a SEGV when accessed.
So, what we do here is cheating for the sake of the autoconf test So, what we do here is cheating for the sake of the autoconf test.
on 64 bit systems. The justification is that there's very likely The justification is that there's very likely no application actually
no application actually utilizing the map beyond EOF, and we know that utilizing the map beyond EOF, and we know that all bytes beyond EOF
all bytes beyond EOF are set to 0 anyway. If this test doesn't work are set to 0 anyway. If this test doesn't work, it will result in
on 64 bit systems, it will result in not using mmap at all in a not using mmap at all in a package. But we want mmap being treated
package. But we want that mmap is treated as usable by autoconf, as usable by autoconf.
regardless whether the autoconf test runs on a 32 bit or a 64 bit
system.
Ok, so we know exactly what autoconf is doing. The file is called Ok, so we know exactly what autoconf is doing. The file is called
"conftest.txt", it has a size of 1 byte, the mapping size is the "conftest.txt", it has a size of 1 byte, the mapping size is the
@ -916,31 +911,19 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
mapping is MAP_SHARED, the offset is 0. mapping is MAP_SHARED, the offset is 0.
If all these requirements are given, we just return an anonymous map. If all these requirements are given, we just return an anonymous map.
This will help to get over the autoconf test even on 64 bit systems.
The tests are ordered for speed. */ The tests are ordered for speed. */
#ifdef __x86_64__ if (len == pagesize
if (1) && prot == (PROT_READ | PROT_WRITE)
#else && flags == MAP_SHARED
if (wincap.is_wow64 ()) && off == 0
#endif && (RtlSplitUnicodePath (fh->pc.get_nt_native_path (), NULL,
{ &fname),
UNICODE_STRING fname; wcscmp (fname.Buffer, L"conftest.txt") == 0)
IO_STATUS_BLOCK io; && NT_SUCCESS (NtQueryInformationFile (fh->get_handle (), &io,
FILE_STANDARD_INFORMATION fsi; &fsi, sizeof fsi,
FileStandardInformation))
if (len == pagesize && fsi.EndOfFile.QuadPart == 1LL)
&& prot == (PROT_READ | PROT_WRITE) flags |= MAP_ANONYMOUS;
&& flags == MAP_SHARED
&& off == 0
&& (RtlSplitUnicodePath (fh->pc.get_nt_native_path (), NULL,
&fname),
wcscmp (fname.Buffer, L"conftest.txt") == 0)
&& NT_SUCCESS (NtQueryInformationFile (fh->get_handle (), &io,
&fsi, sizeof fsi,
FileStandardInformation))
&& fsi.EndOfFile.QuadPart == 1LL)
flags |= MAP_ANONYMOUS;
}
} }
if (anonymous (flags) || fd == -1) if (anonymous (flags) || fd == -1)
@ -1025,20 +1008,8 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
goto go_ahead; goto go_ahead;
} }
fsiz -= off; fsiz -= off;
/* We're creating the pages beyond EOF as reserved, anonymous pages. /* We're creating the pages beyond EOF as reserved, anonymous
Note that 64 bit environments don't support the AT_ROUND_TO_PAGE pages if MAP_AUTOGROW is not set. */
flag, which is required to get this right for the remainder of
the first 64K block the file ends in. We perform the workaround
nevertheless to support expectations that the range mapped beyond
EOF can be safely munmap'ed instead of being taken by another,
totally unrelated mapping. */
if ((off_t) len > fsiz && !autogrow (flags))
orig_len = len;
#ifdef __i386__
else if (!wincap.is_wow64 () && roundup2 (len, wincap.page_size ())
< roundup2 (len, pagesize))
orig_len = len;
#endif
if ((off_t) len > fsiz) if ((off_t) len > fsiz)
{ {
if (autogrow (flags)) if (autogrow (flags))
@ -1053,9 +1024,12 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
} }
} }
else else
/* Otherwise, don't map beyond EOF, since Windows would change {
the file to the new length, in contrast to POSIX. */ /* Otherwise, don't map beyond EOF, since Windows would change
len = fsiz; the file to the new length, in contrast to POSIX. */
orig_len = len;
len = fsiz;
}
} }
/* If the requested offset + len is <= file size, drop MAP_AUTOGROW. /* If the requested offset + len is <= file size, drop MAP_AUTOGROW.
@ -1088,6 +1062,7 @@ go_ahead:
} }
} }
orig_len = roundup2 (orig_len, pagesize);
#ifdef __x86_64__ #ifdef __x86_64__
if (!wincap.has_extended_mem_api ()) if (!wincap.has_extended_mem_api ())
addr = mmap_alloc.alloc (addr, orig_len ?: len, fixed (flags)); addr = mmap_alloc.alloc (addr, orig_len ?: len, fixed (flags));
@ -1099,7 +1074,6 @@ go_ahead:
deallocated and the address we got is used as base address for the deallocated and the address we got is used as base address for the
subsequent real mappings. This ensures that we have enough space subsequent real mappings. This ensures that we have enough space
for the whole thing. */ for the whole thing. */
orig_len = roundup2 (orig_len, pagesize);
PVOID newaddr = VirtualAlloc (addr, orig_len, MEM_TOP_DOWN | MEM_RESERVE, PVOID newaddr = VirtualAlloc (addr, orig_len, MEM_TOP_DOWN | MEM_RESERVE,
PAGE_READWRITE); PAGE_READWRITE);
if (!newaddr) if (!newaddr)
@ -1132,51 +1106,18 @@ go_ahead:
if (orig_len) if (orig_len)
{ {
/* If the requested length is bigger than the file size, the /* If the requested length is bigger than the file size, the
remainder is created as anonymous mapping. Actually two remainder is created as anonymous mapping, as reserved pages which
mappings are created, first the remainder from the file end to raise a SIGBUS when trying to access them. This results in an
the next 64K boundary as accessible pages with the same allocation gap in the first 64K block the file ends in, but there's
protection as the file's pages, then as much pages as necessary nothing at all we can do about that. */
to accomodate the requested length, but as reserved pages which len = roundup2 (len, pagesize);
raise a SIGBUS when trying to access them. AT_ROUND_TO_PAGE
and page protection on shared pages is only supported by the
32 bit environment, so don't even try on 64 bit or even WOW64.
This results in an allocation gap in the first 64K block the file
ends in, but there's nothing at all we can do about that. */
#ifdef __x86_64__
len = roundup2 (len, wincap.allocation_granularity ());
orig_len = roundup2 (orig_len, wincap.allocation_granularity ());
#else
len = roundup2 (len, wincap.is_wow64 () ? wincap.allocation_granularity ()
: wincap.page_size ());
#endif
if (orig_len - len) if (orig_len - len)
{ {
orig_len -= len; size_t sigbus_page_len = orig_len - len;
size_t valid_page_len = 0;
#ifndef __x86_64__
if (!wincap.is_wow64 ())
valid_page_len = orig_len % pagesize;
#endif
size_t sigbus_page_len = orig_len - valid_page_len;
caddr_t at_base = base + len;
if (valid_page_len)
{
prot |= __PROT_FILLER;
flags &= MAP_SHARED | MAP_PRIVATE;
flags |= MAP_ANONYMOUS | MAP_FIXED;
at_base = mmap_worker (NULL, &fh_anonymous, at_base,
valid_page_len, prot, flags, -1, 0, NULL);
if (!at_base)
{
fh->munmap (fh->get_handle (), base, len);
set_errno (ENOMEM);
goto out_with_unlock;
}
at_base += valid_page_len;
}
if (sigbus_page_len) if (sigbus_page_len)
{ {
caddr_t at_base = base + len;
prot = PROT_READ | PROT_WRITE | __PROT_ATTACH; prot = PROT_READ | PROT_WRITE | __PROT_ATTACH;
flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED; flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED;
at_base = mmap_worker (NULL, &fh_anonymous, at_base, at_base = mmap_worker (NULL, &fh_anonymous, at_base,

View File

@ -51,10 +51,6 @@ extern GUID __cygwin_socket_guid;
#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 #define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080
#define FILE_DEVICE_SECURE_OPEN 0x00000100 #define FILE_DEVICE_SECURE_OPEN 0x00000100
/* Allocation type values in NtMapViewOfSection call. */
#define AT_EXTENDABLE_FILE 0x00002000
#define AT_ROUND_TO_PAGE 0x40000000
/* Lock type in NtLockVirtualMemory/NtUnlockVirtualMemory call. */ /* Lock type in NtLockVirtualMemory/NtUnlockVirtualMemory call. */
#define MAP_PROCESS 1 #define MAP_PROCESS 1
#define MAP_SYSTEM 2 #define MAP_SYSTEM 2