1

为什么以下代码可以正常工作?

void continuous_mmap (void)
{
 struct stat buf;
 int fd = open("file_one", O_RDONLY), i;
 char *contents;

 fstat(fd, &buf);
 contents = mmap(NULL, buf.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0);
 close (fd);
 mprotect(contents, buf.st_size, PROT_READ);
 for (i = 0; i < 15; i++) {
  printf ("%s\n", contents);
  sleep (1);
 }
 munmap(contents, buf.st_size);
}

首先,文件保持同步(在外部编辑和保存文件会自动打印更新的内容),即使附加到。我的代码如何能够在没有段错误的情况下访问超出我映射的字节数(初始文件大小)?是因为mmap总是将长度四舍五入到系统页面大小吗?如果是这样,这种行为是否可以依赖于一般系统(我在手册页POSIX中找不到任何这样的要求)。mmap

其次,文本如何自动附加一个'0'?是因为非映射字节自动归零吗?这种行为可以依赖吗?

4

3 回答 3

2

是的,标准说

系统应始终在对象末尾对任何部分页面进行零填充。此外,系统绝不会写出对象最后一页超出其末尾的任何修改部分。

  • 如果是这样,这种行为是否可以依赖于一般的 POSIX 系统(我在 mmap 手册页中找不到任何这样的要求)。

不,我不会那样做,并不是所有的实现都符合要求。我至少见过一次非常糟糕的实现。

您不应为此使用mmap调用的此功能,而应ftruncate根据需要延长文件。

于 2010-11-11T08:02:42.127 回答
1

POSIX 甚至不要求一个重要的页面大小。从理论上讲,实现可以具有 1 个字节的“页面”大小。同样,似乎没有指定从文件大小之后的页面其余部分读取零。我可以想象一些损坏的实现会泄漏此处截断的旧文件内容,但我认为这是一个重大的安全/隐私漏洞,这将使这种实现在现实世界中变得无关紧要。当然,他们可以填充空间,0xDEADBEEF然后你会不走运。

即使您可以假设零填充(大多数现实世界的操作系统可能都是这种情况),我也会告诫不要使用它。如果您的文件恰好是系统页面大小的倍数,会发生什么?突然,您的代码在读取结束时崩溃,或者(可能更糟)从恰好映射到文件映射附近的不相关页面读取。这是一个非常非常讨厌的错误,您可能无法捕捉到,因为文本文件恰好是系统页面大小的倍数的可能性非常低。

于 2010-11-11T07:49:25.460 回答
0

您看到文件的外部更新(即使它已映射MAP_PRIVATE)的原因是您尚未写入映射,因此系统尚未为您提供文件页面的私有副本。这种行为是允许的,但不是必需的。

如果您contents[0]在循环之前修改了应用程序,它将不到外部更改。

于 2010-11-11T10:41:16.350 回答