14

在 Linux 中,mmap(2) 手册页解释了匿名映射

. . . 没有任何文件支持;它的内容被初始化为零。

FreeBSD mmap(2) 手册页没有对零填充做出类似的保证,尽管它确实承诺在非匿名映射中文件结尾之后的字节是零填充的。

哪些 Unix 版本承诺从匿名 mmap 返回零初始化内存?哪些在实践中返回零初始化内存,但在他们的手册页上没有做出这样的承诺?

我的印象是,零填充部分是出于安全原因。我想知道是否有任何 mmap 实现跳过了对被 mmaped、munmapped、然后由单个进程再次 mmaped 的页面的零填充,或者是否有任何实现用伪随机位或一些非零常量填充新映射的页面。

PS显然,甚至 brk 和 sbrk 也用来保证零填充页面。我在 Linux 上的实验似乎表明,即使完整页面在 sbrk 调用分配它们后在页面错误时被零填充,部分页面也不会:

#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]);
}
4

2 回答 2

7

如果不简单地详尽列举所有手册页或其他发布文档,很难说哪些承诺是什么,但处理的底层代码MAP_ANON(通常?总是?)也用于在 bss 空间中映射可执行文件,并且 bss 空间需要为零-填充。所以很有可能。

至于“还给你旧值”(或一些非零值,但很可能是旧值),如果您取消映射并重新映射,那么如果某些系统对释放“懒惰”,这当然是可能的。我只使用了几个一mmap开始就支持的系统(BSD 和 Linux 衍生产品),而且没有一个是懒惰的,至少在内核代码处理方面没有mmap

原因sbrk可能会或可能不会零填充“重新增长”的页面可能与历史相关,或者缺乏历史。当前的 FreeBSD 代码与我从旧的、早期的回忆相匹配mmap:有两个半秘密变量,minbrkcurbrk,并且brk只有当它们移动到一个至少为的值sbrk时才会调用(真正的系统调用) . (实际上,这看起来有点不正常:至少具有行为,但只是将其参数添加到并调用。似乎无害,因为内核检查in ,因此太负会因 . 而失败。)SYS_breakcurbrkminbrkbrksbrkcurbrkSYS_breaksys_obreak()/sys/vm/vm_unix.csbrk()EINVAL

我必须查看 Linux C 库(然后可能还有内核代码),但它可能会简单地忽略“降低中断”的尝试,而只是在 libc 中记录一个“逻辑中断”值。如果您有mmap()并且没有向后兼容性要求,则可以使用匿名映射完全在 libc 中实现,brk()并且sbrk()将它们都实现为“仅增长”将是微不足道的,因为它是。

于 2013-07-27T08:59:03.503 回答
5

哪些 Unix 版本承诺从匿名 mmap 返回零初始化内存?

GNU/Linux

正如您在问题中所说,mmap 的 Linux 版本承诺零填充匿名映射:

MAP_ANONYMOUS

映射没有任何文件支持;它的内容被初始化为零。

NetBSD

NetBSD 版本的 mmap承诺零填充匿名映射:

MAP_ANON

映射与任何特定文件无关的匿名内存。文件描述符不用于创建MAP_ANON区域,必须指定为-1. 映射的内存将被零填充。

OpenBSD

mmap的OpenBSD 联机帮助页不承诺零填充匿名映射。然而,Theo de Raadt(著名的 OpenBSD 开发人员)于2019 年 11 月在 OpenBSD 邮件列表中声明:

当然它是零填充的。还会是什么?没有合理的替代方案。

我认为说这么明显的话会损害信息的其余部分。

其他 OpenBSD 开发人员并没有反驳他。

IBM AIX

AIX 版本的mmap承诺零填充匿名映射:

MAP_ANONYMOUS

指定创建一个初始化为全零的新的匿名内存区域。

惠普-UX

根据 nixdoc.net,HP-UX 版本的 mmap承诺零填充匿名映射:

如果MAP_ANONYMOUS设置为flags,则创建一个新的内存区域并将其初始化为全零。

索拉里斯

Solaris 版本的mmap承诺零填充匿名映射:

WhenMAP_ANON设置为flags,并fildes设置为 -1,mmap()提供了将匿名页面返回给调用者的直接路径。此操作等效于从参数中省略传递mmap()打开的文件描述符。/dev/zeroMAP_ANONflags

这个 Solaris 手册页为我们提供了一种获取零填充内存页面的方法,而无需依赖与标志一起使用的 mmap 的行为MAP_ANONYMOUS:不使用MAP_ANONYMOUS标志,并创建由/dev/zero文件支持的映射。了解提供文件的类 Unix 操作系统列表会很有用/dev/zero,以查看这种方法是否比使用MAP_ANONYMOUS标志更便携(/dev/zeroMAP_ANONYMOUS 都不是 POSIX)。

有趣的是,维基百科关于 /dev/zero的文章声称在创建匿名映射时MAP_ANONYMOUS不需要打开。/dev/zero

于 2020-12-01T04:30:22.627 回答