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
{
/* Zero len creates mapping for whole file and allows
AT_EXTENDABLE_FILE mapping, if we ever use it... */
/* Zero len creates mapping for whole file */
sectionsize.QuadPart = 0;
status = NtCreateSection (&h, SECTION_ALL_ACCESS, &oa, &sectionsize,
protect, attributes, fhdl);
@ -195,12 +194,7 @@ MapView (HANDLE h, void *addr, size_t len, DWORD openflags,
DWORD protect = gen_create_protect (openflags, flags);
void *base = addr;
SIZE_T viewsize = len;
#ifdef __x86_64__ /* AT_ROUND_TO_PAGE isn't supported on 64 bit systems. */
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__
/* 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)
{
UNICODE_STRING fname;
IO_STATUS_BLOCK io;
FILE_STANDARD_INFORMATION fsi;
/* Ensure that fd is open */
cygheap_fdget cfd (fd);
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
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
64 bit systems. The file mapping will be only a single page, 4K, and
since 64 bit systems don't support the AT_ROUND_TO_PAGE flag, the
remainder of the 64K slot will result in a SEGV when accessed.
what POSIX requires. The problem is, we can't create that mapping.
The file mapping will be only a single page, 4K, and the 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
on 64 bit systems. The justification is that there's very likely
no application actually utilizing the map beyond EOF, and we know that
all bytes beyond EOF are set to 0 anyway. If this test doesn't work
on 64 bit systems, it will result in not using mmap at all in a
package. But we want that mmap is treated as usable by autoconf,
regardless whether the autoconf test runs on a 32 bit or a 64 bit
system.
So, what we do here is cheating for the sake of the autoconf test.
The justification is that there's very likely no application actually
utilizing the map beyond EOF, and we know that all bytes beyond EOF
are set to 0 anyway. If this test doesn't work, it will result in
not using mmap at all in a package. But we want mmap being treated
as usable by autoconf.
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
@ -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.
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. */
#ifdef __x86_64__
if (1)
#else
if (wincap.is_wow64 ())
#endif
{
UNICODE_STRING fname;
IO_STATUS_BLOCK io;
FILE_STANDARD_INFORMATION fsi;
if (len == pagesize
&& prot == (PROT_READ | PROT_WRITE)
&& 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 (len == pagesize
&& prot == (PROT_READ | PROT_WRITE)
&& 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)
@ -1025,20 +1008,8 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
goto go_ahead;
}
fsiz -= off;
/* We're creating the pages beyond EOF as reserved, anonymous pages.
Note that 64 bit environments don't support the AT_ROUND_TO_PAGE
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
/* We're creating the pages beyond EOF as reserved, anonymous
pages if MAP_AUTOGROW is not set. */
if ((off_t) len > fsiz)
{
if (autogrow (flags))
@ -1053,9 +1024,12 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, off_t off)
}
}
else
/* Otherwise, don't map beyond EOF, since Windows would change
the file to the new length, in contrast to POSIX. */
len = fsiz;
{
/* Otherwise, don't map beyond EOF, since Windows would change
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.
@ -1088,6 +1062,7 @@ go_ahead:
}
}
orig_len = roundup2 (orig_len, pagesize);
#ifdef __x86_64__
if (!wincap.has_extended_mem_api ())
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
subsequent real mappings. This ensures that we have enough space
for the whole thing. */
orig_len = roundup2 (orig_len, pagesize);
PVOID newaddr = VirtualAlloc (addr, orig_len, MEM_TOP_DOWN | MEM_RESERVE,
PAGE_READWRITE);
if (!newaddr)
@ -1132,51 +1106,18 @@ go_ahead:
if (orig_len)
{
/* If the requested length is bigger than the file size, the
remainder is created as anonymous mapping. Actually two
mappings are created, first the remainder from the file end to
the next 64K boundary as accessible pages with the same
protection as the file's pages, then as much pages as necessary
to accomodate the requested length, but as reserved pages which
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
remainder is created as anonymous mapping, as reserved pages which
raise a SIGBUS when trying to access them. 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. */
len = roundup2 (len, pagesize);
if (orig_len - 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;
size_t sigbus_page_len = orig_len - 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)
{
caddr_t at_base = base + len;
prot = PROT_READ | PROT_WRITE | __PROT_ATTACH;
flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED;
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_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. */
#define MAP_PROCESS 1
#define MAP_SYSTEM 2