[PATCH] Cygwin: mmap: use 64K pages for bookkeeping
Ken Brown
kbrown@cornell.edu
Fri Jan 17 23:22:37 GMT 2025
On 1/15/2025 12:31 PM, Corinna Vinschen wrote:
>> Ouch. It looks like we can't go to 64K bookkeeping. Windows files are
>> not length-aligned to 64K allocation granularity, but to 4K pagesize.
>> Thus, if we align the length to 64K in mprotect or
>> mmap_record::unmap_pages, it tries to access the unallocatd area from
>> the EOF page to the last page in the 64K area, which, obviously fails.
>
> Alternatively it has to be faked in the affected functions, which then
> stealthily only access the pages up to EOF under the hood...
It's possible that the following simple patch (on top of the previous
patch) solves the problem:
--- a/winsup/cygwin/mm/mmap.cc
+++ b/winsup/cygwin/mm/mmap.cc
@@ -409,16 +409,28 @@ mmap_record::find_unused_pages (SIZE_T pages) const
/* Return true if the interval I from addr to addr + len intersects
the interval J of this mmap_record. The endpoint of the latter is
- first rounded up to a page boundary. If there is an intersection,
- then it is the interval from m_addr to m_addr + m_len. The
- variable 'contains' is set to true if J contains I.
+ first rounded up to a Windows page boundary. If there is an
+ intersection, then it is the interval from m_addr to
+ m_addr + m_len. The variable 'contains' is set to true if J contains I.
+
+ It is necessary to use a 4K Windows page boundary above because
+ Windows files are length-aligned to 4K pages, not to the 64K
+ allocation granularity. If we were to align the record length to
+ 64K, then callers of this function might try to access the
+ unallocated memory from the EOF page to the last page in the 64K
+ area. See
+
+ https://cygwin.com/pipermail/cygwin-patches/2025q1/013240.html
+
+ for an example in which mprotect and mmap_record::unmap_pages both
+ fail when we align the record length to 64K.
*/
bool
mmap_record::match (caddr_t addr, SIZE_T len, caddr_t &m_addr, SIZE_T
&m_len,
bool &contains)
{
contains = false;
- SIZE_T rec_len = PAGE_CNT (get_len ()) *
wincap.allocation_granularity ();
+ SIZE_T rec_len = roundup2 (get_len (), wincap.page_size ());
caddr_t low = MAX (addr, get_address ());
caddr_t high = MIN (addr + len, get_address () + rec_len);
if (low < high)
I've checked that gdb functions normally after this patch, but I can't
claim to have thought through all possible situations where an
mmap-related function might fail as a result of switching to 64K
bookkeeping.
Ken
More information about the Cygwin-patches
mailing list