【问题标题】:Anonymous mmap zero-filled?匿名 mmap 零填充?
【发布时间】:2013-07-06 17:27:53
【问题描述】:

In Linux, the mmap(2) man page 解释说匿名映射

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

The FreeBSD mmap(2) man page 没有对零填充做出类似的保证,但它确实承诺在非匿名映射中文件末尾之后的字节是零填充的。

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

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

附: Apparently, even brk and sbrk used to guarantee zero-filled pages.我在 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]);
}

【问题讨论】:

    标签: memory freebsd mmap


    【解决方案1】:

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

    GNU/Linux

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

    MAP_ANONYMOUS

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

    NetBSD

    NetBSD version of mmap 承诺零填充匿名映射:

    MAP_ANON

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

    OpenBSD

    OpenBSD manpage of mmap 不承诺零填充匿名映射。然而,Theo de Raadt(著名的 OpenBSD 开发人员)在November 2019 on the OpenBSD mailing list 中声明:

    当然是零填充。还会是什么?没有可行的替代方案。

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

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

    IBM AIX

    AIX version of mmap 承诺零填充匿名映射:

    MAP_ANONYMOUS

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

    HP-UX

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

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

    Solaris

    Solaris version of mmap 承诺零填充匿名映射:

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

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

    有趣的是,Wikipedia article about /dev/zero 声称引入MAP_ANONYMOUS 是为了在创建匿名映射时无需打开/dev/zero

    【讨论】:

      【解决方案2】:

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

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

      sbrk 可能会或可能不会对“重新生成”页面进行零填充的原因可能与历史或缺乏历史有关。当前的 FreeBSD 代码与我记得的旧的 mmap 之前的代码相匹配:有两个半秘密变量 minbrkcurbrkbrksbrk 都只会调用 @987654330 @(真正的系统调用)如果他们将curbrk 移动到至少为minbrk 的值。 (实际上,这看起来有点破损:brk 具有至少行为,但sbrk 只是将其参数添加到curbrk 并调用SYS_break。由于内核检查,sys_obreak() 中的/sys/vm/vm_unix.c 似乎无害,因此过于消极的sbrk() 将失败并显示EINVAL。)

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

      【讨论】:

      • 直到我查了才知道这一点,但 MAP_ANON 不在 POSIX 中。
      • @Olsonist:这有点令人惊讶,但它增加了“没有关于 MAP_ANON 的硬性承诺”,以至于甚至没有承诺 MAP_ANON 会存在。 :-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-18
      • 2012-07-09
      • 1970-01-01
      相关资源
      最近更新 更多