Hi Ben, On 2026-04-23T12:44:14-0400, Ben Kallus wrote: > The man page states that MAP_GROWSDOWN can only cause a mapping to > grow by a single page. This is incorrect; mappings can grow by many > pages at a time, until reaching either the stack size limit or growing > too close to another mapping. > > To observe that mappings can grow by more than one page, and that they > are limited by the stack size limit, run the following C program with a > stack size limit of 0x800000 bytes, and then again with a stack size limit > of 0x801000 bytes, and observe that it segfaults as the comments describe. Would you mind pasting a shell session that runs it with both stack limits? > > > struct page { > > char data[4096]; > > }; > > static_assert(sizeof(struct page) == 4096); > > > > void *const BASE_ADDRESS = (void *)0xabcdef000; I'd prefer upper-casing the hex value, to differentiate it visually from the 'x': 0xABCDEF000; If this seems too packed, C23 now allows using a digit separator: alx@devuan:~/tmp$ cat s.c void *const BASE_ADDRESS = (void *)0xA'BCDE'F000; alx@devuan:~/tmp$ gcc -Wall -Wextra -S s.c alx@devuan:~/tmp$ > > > > int main(int const argc, char const * const * const argv) { Unrelated, but you can define int main(void) without parameters. That's allowed by ISO C. Here's a quote of C23, but this is allowed by any version of ISO C: 5.1.2.3.2 Program startup 1 The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters: int main(void) { /* ... */ } or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared): int main(int argc, char *argv[]) { /* ... */ } or equivalent;6) or in some other implementation-defined manner. > > volatile struct page *p = mmap( > > BASE_ADDRESS, > > 1, > > PROT_READ | PROT_WRITE, > > MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN | MAP_FIXED_NOREPLACE, > > -1, > > 0 > > ); > > // stack_limit=0x800000 // stack_limit=0x801000 > > (p - 2047)->data[0] = 0; // no segfault // no segfault > > (p - 2048)->data[0] = 0; // segfault // no segfault > > (p - 2049)->data[0] = 0; // segfault // segfault > > } > > To observe that mappings stop growing when they get within 256 pages of > the next lower mapping (instead of a single page, as the man page > currently states), run the following program, and observe that it > segfaults as the comments describe. Would you mind running the program and pasting that here too? > > > struct page { > > char data[4096]; > > }; > > static_assert(sizeof(struct page) == 4096); > > > > struct page *const BASE_ADDRESS = (void *)0xabcdef000; > > > > int main(int const argc, char const * const * const argv) { > > volatile struct page *p = mmap( > > BASE_ADDRESS, > > 1, > > PROT_READ | PROT_WRITE, > > MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN | MAP_FIXED_NOREPLACE, > > -1, > > 0 > > ); > > > > struct page *p2 = mmap( > > BASE_ADDRESS - 258, > > 1, > > PROT_READ | PROT_WRITE, > > MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, > > -1, > > 0 > > ); > > > > // no segfault (causes p to grow by a page) > > (p - 1)->data[0] = 0; > > > > // unmap the test page > > munmap(p2, 1); > > > > // unmap the new page from p growing > > munmap((struct page *)p - 1, 1); > > > > struct page *p3 = mmap( > > BASE_ADDRESS - 257, > > 1, > > PROT_READ | PROT_WRITE, > > MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, > > -1, > > 0 > > ); > > > > // segfault because p can't grow due to proximity to p3 > > (p - 1)->data[0] = 0; > > } > > Fixes: 176b1a76 (2016-11-21; "mmap.2: Add (much) more detail on MAP_GROWSDOWN") > Signed-off-by: Ben Kallus > --- > man/man2/mmap.2 | 10 +++++----- > 1 file changed, 5 insertions(+), 5 deletions(-) > > diff --git a/man/man2/mmap.2 b/man/man2/mmap.2 > index 20b94c243..925b18ffc 100644 > --- a/man/man2/mmap.2 > +++ b/man/man2/mmap.2 > @@ -276,11 +276,11 @@ should check the returned address against the requested address. > This flag is used for stacks. > It indicates to the kernel virtual memory system that the mapping > should extend downward in memory. > -Touching an address in the "guard" page below the mapping will cause > -the mapping to grow by a page. > -This growth can be repeated until the mapping grows to within a > -page of the high end of the next lower mapping, > -at which point touching the "guard" page will result in a > +Touching an address below the mapping will cause the mapping to grow to > +accommodate the access. > +This growth can be repeated until the mapping crosses the stack size limit, > +or grows to within 256 pages of the high end of the next lower mapping, > +at which point accessing below the mapping will result in a Thanks! The diff seems reasonable. Please adjust the commit message and resend. Have a lovely day! Alex > .B SIGSEGV > signal. > .TP > -- > 2.54.0 > --