Re: [PATCH] man/man2/mmap.2: Document when MAP_GROWSDOWN does/doesn't trigger growth
Alejandro Colomar <[email protected]>
| Newsgroups | org.kernel.vger.linux-man |
|---|---|
| Message-ID | <afiVz8xRiJ0jQzXZ@devuan> |
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.
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#paragraph.5.1.2.3.2>
> > 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 <[email protected]>
> ---
> 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
>
--
<https://www.alejandro-colomar.es>
signature.asc
(application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmn4mIMACgkQ64mZXMKQ wqkcHRAArzGMZv/VlYJfaF1ZLdF36GQHsDFxGQpXXlvL5iM4O7iGPm88nnhMoUAi pMyn2DPP1yPHGREcJkgFvUB1K+4vNggzWzfW8YoA5AxE1NvLEmxGmtQkF3jrYJXN 9Pa/2BK7t27gEektOJypkfWUbnBhw4Tp91v4I9yjrLd7R/hax8+nqEVgENveSkoX 7Opq52EPt87l2cCaIkpAeTwPTBReT3IC5bPgWoej0hBEQfZrik76k1gTf41pKO2+ ba1K9MqEOfrNGthmlCnvIEqPnBTBW8Z68Y4BFeyr1EZOBO0ye8GYaATZzXXMyQVu EdfBt/07emPo7A0Q9/82b3gY5kckjJJuqO2LKy8V4Nq8ORY2uTmgvSftN9SmOjCk eEGZBQ+49XiYBnLQXbwWpyeDePCoDzYNJSKYLzGOpILmktDS2clRyTQwGgKdEDY1 02xF7EdBu8L1Ze6ToRdzM/A3qiXspVkiPr7YUbYYiSclXAycJuMl/KYnxW8ztCSq HmszYIfm8537LulL3aO1dUaLP07yZy4MDff1bt0WkRgkSC7O409J4m60wZFpEmsE mYrxt7W5XHaYDy9A/4a8D28UlD/vt3oIm3kNM7sfe+VblnGfJo8JZXZ+tWrPszvl /w3JFCJvcNggQ5UndweLctP8D7wAc4MYvSvD97gRegGwjtTdPz4= =H9ub -----END PGP SIGNATURE-----