In Linux, the mmap(2) man page解释了匿名映射
。 。 。没有任何文件支持;其内容初始化为零。
The FreeBSD mmap(2) man page没有对零填充做出类似的保证,尽管它确实保证非匿名映射中文件结尾后的字节为零填充。
哪种Unix承诺从匿名mmaps返回零初始化内存?哪些在实践中返回零初始化内存,但在他们的手册页上没有做出这样的承诺?
我的印象是零填充部分是出于安全原因。我想知道是否有任何mmap实现跳过对mmap,munmap,然后由单个进程再次mmapped的页面的零填充,或者如果任何实现用伪随机位填充新映射的页面,或者某些非零常量。
P.S。 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]);
}
答案 0 :(得分:7)
如果没有简单地详尽列举所有手册页或其他发布文档,很难说哪些承诺是什么,但处理MAP_ANON
的底层代码(通常?总是?)也用于在bss空间中映射可执行文件和bss空间需要填零。所以这很可能。
至于“给你回旧的价值”(或者一些非零值,但很可能是你的旧值),如果你取消映射并重新映射,如果某些系统是“懒惰的”,这似乎是可能的关于解除分配。我首先只使用了一些支持mmap
的系统(BSD和Linux衍生产品),而且这两种系统都不是那么懒,至少在内核代码处理mmap
中没有。
sbrk
可能会或可能不会填充“重新生成”页面的原因可能与历史记录或缺乏历史记录有关。当前的FreeBSD代码与我在旧mmap
天之前回忆的内容相匹配:有两个半秘密变量,minbrk
和curbrk
,以及brk
和sbrk
只会在SYS_break
移动到至少为curbrk
的值时调用minbrk
(真正的系统调用)。 (实际上,这看起来有点破碎:brk
具有至少行为,但sbrk
只是将其参数添加到curbrk
并调用SYS_break
。由于内核检查,似乎无害sys_obreak()
位于/sys/vm/vm_unix.c
,因此过于负面的sbrk()
会因EINVAL
而失败。)
我必须查看Linux C库(然后也可能是内核代码),但它可能只是忽略“降低中断”的尝试,而只是在libc中记录“逻辑中断”值。如果您有mmap()
且没有向后兼容性要求,则可以使用匿名映射在libc中完全实现brk()
和sbrk()
,并且将它们实现为“增长”将是微不足道的。只是“,就像它一样。”
答案 1 :(得分:1)
哪种类型的Unix承诺从匿名mmap返回零初始化的内存?
正如您在问题中所说,Linux version of mmap承诺零填充匿名映射:
MAP_ANONYMOUS
映射没有任何文件支持;其内容初始化为零。
NetBSD version of mmap承诺零填充匿名映射:
MAP_ANON
映射匿名内存,该内存不与任何特定文件关联。文件描述符不用于创建
MAP_ANON
区域,而必须指定为-1
。映射的内存将为零。
OpenBSD manpage of mmap不承诺将零填充匿名映射。但是,Theo de Raadt(著名的OpenBSD开发人员)在November 2019 on the OpenBSD mailing list中声明:
当然是零填充。还有什么呢?没有任何可行的选择。
我认为这很明显地削弱了消息的其余部分。
其他OpenBSD开发人员并不与他矛盾。
AIX version of mmap承诺零填充匿名映射:
MAP_ANONYMOUS
指定创建一个初始化为全零的新的匿名内存区域。
根据nixdoc.net,HP-UX version of mmap承诺零填充匿名映射:
如果在
MAP_ANONYMOUS
中设置了flags
,则会创建一个新的内存区域并将其初始化为全零。
Solaris version of mmap承诺零填充匿名映射:
在
MAP_ANON
中设置flags
,并且将fildes
设置为-1时,mmap()
提供了将匿名页面返回给调用者的直接路径。此操作等效于在{{1}上通过mmap()
参数省略/dev/zero
在MAP_ANON
上向flags
传递打开文件描述符。
此Solaris手册页为我们提供了一种获取零填充内存页面的方法,而无需依靠与MAP_ANONYMOUS
标志一起使用的mmap的行为:请勿使用MAP_ANONYMOUS
标志并创建映射由/dev/zero
文件支持。了解提供/dev/zero
文件的类Unix操作系统列表,以查看这种方法是否比使用MAP_ANONYMOUS
标志(/dev/zero或{{ 3}}是POSIX)。
有趣的是,MAP_ANONYMOUS声称引入MAP_ANONYMOUS
是为了消除创建匿名映射时打开/dev/zero
的需要。