Anonymous mmap zero-filled?

freebsd, memory, mmap

Solution

Which flavors of Unix promise to return zero-initialized memory from anonymous mmaps?

GNU/Linux

As you said in your question, the Linux version of mmap promises to zero-fill anonymous mappings:

`MAP_ANONYMOUS`

The mapping is not backed by any file; its contents are initialized to zero.

NetBSD

The NetBSD version of mmap promises to zero-fill anonymous mappings:

`MAP_ANON`

Map anonymous memory not associated with any specific file. The file descriptor is not used for creating `MAP_ANON` regions, and must be specified as `-1`. The mapped memory will be zero filled.

OpenBSD

The OpenBSD manpage of mmap does not promise to zero-fill anonymous mappings. However, Theo de Raadt (prominent OpenBSD developer), declared in November 2019 on the OpenBSD mailing list:

Of course it is zero filled. What else would it be? There are no plausible alternatives.

I think it detracts from the rest of the message to say something so obvious.

And the other OpenBSD developers did not contradict him.

IBM AIX

The AIX version of mmap promises to zero-fill anonymous mappings:

`MAP_ANONYMOUS`

Specifies the creation of a new, anonymous memory region that is initialized to all zeros.

HP-UX

According to nixdoc.net, the HP-UX version of mmap promises to zero-fill anonymous mappings:

If `MAP_ANONYMOUS` is set in `flags`, a new memory region is created and initialized to all zeros.

Solaris

The Solaris version of mmap promises to zero-fill anonymous mappings:

When `MAP_ANON` is set in `flags`, and `fildes` is set to -1, `mmap()` provides a direct path to return anonymous pages to the caller. This operation is equivalent to passing `mmap()` an open file descriptor on `/dev/zero` with `MAP_ANON` elided from the `flags` argument.

This Solaris man page gives us a way to get zero-filled memory pages without relying on the behavior of mmap used with the `MAP_ANONYMOUS` flag: do not use the `MAP_ANONYMOUS` flag, and create a mapping backed by the `/dev/zero` file. It would be useful to know the list of Unix-like operating systems providing the `/dev/zero` file, to see if this approach is more portable than using the `MAP_ANONYMOUS` flag (neither /dev/zero nor MAP_ANONYMOUS are POSIX).

Interestingly, the Wikipedia article about /dev/zero claims that `MAP_ANONYMOUS` was introduced to remove the need of opening `/dev/zero` when creating an anonymous mapping.

Problem

In Linux, the mmap(2) man page explains that an anonymous mapping . . . is not backed by any file; its contents are initialized to zero. The FreeBSD mmap(2) man page does not make a similar guarantee about zero-filling, though it does promise that bytes after the end of a file in a non-anonymous mapping are zero-filled. Which flavors of Unix promise to return zero-initialized memory from anonymous mmaps? Which ones return zero-initialized memory in practice, but make no such promise on their man pages? It is my impression that zero-filling is partially for security reasons. I wonder if any mmap implementations skip the zero-filling for a page that was mmapped, munmapped, then mmapped again by a single process, or if any implementations fill a newly mapped page with pseudorandom bits, or some non-zero constant. P.S. Apparently, even brk and sbrk used to guarantee zero-filled pages. My experiments on Linux seem to indicate that, even if full pages are zero-filled upon page fault after a sbrk call allocates them, partial pages are not: ``` #include <unistd.h> #include <stdio.h> int main() { const intptr_t many = 100; char * start = sbrk(0); sbrk(many); for (intptr_t i = 0; i < many; ++i) { start[i] = 0xff; } printf("%d\n",(int)start[many/2]); sbrk(many/-2); sbrk(many/2); printf("%d\n",(int)start[many/2]); sbrk(-1 * many); sbrk(many/2); printf("%d\n",(int)start[0]); } ```

Original source