POSIX 系统上的内存映射文件保持同步

发布于 2024-10-02 05:33:46 字数 668 浏览 6 评论 0原文

为什么下面的代码可以正确运行?

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' ?是因为非映射字节自动归零吗?这种行为可以依赖吗?

Why does the following code work correctly?

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);
}

Firstly, the file stays in sync (editing and saving the file externally automatically prints the updated contents), even when appended to. How is my code able to access beyond the number of bytes I've mapped (the initial file size) without segfaulting? Is it because mmap always rounds up the length to the system page size? If so, can this behavior be depended upon on POSIX systems in general (I could not find any such requirement in the mmap man page).

Secondly, how does the text automatically get appended with a '0'? Is it because the non-mapped bytes are automatically zeroed? Can this behavior be depended upon?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泅人 2024-10-09 05:33:46

是的,标准说

系统应始终将任何
对象末尾的部分页面。
此外,系统永远不会写
删除最后一个的任何修改部分
超出其范围的对象的页面
结束。

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

不,我不会这样做,并非所有实现都如此一致。我至少见过一次相当糟糕的实现。

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

yes the standard says

The system shall always zero-fill any
partial page at the end of an object.
Further, the system shall never write
out any modified portions of the last
page of an object which are beyond its
end.

  • If so, can this behavior be depended
    upon on POSIX systems in general (I
    could not find any such requirement
    in the mmap man page).

no, I wouldn't do that, not all implementations may be as conforming. I have seen at least one quite broken implementation, once.

You should not use this feature of the mmap call for this but ftruncate to lengthen your file to your needs.

没︽人懂的悲伤 2024-10-09 05:33:46

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

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

POSIX does not even mandate a nontrivial page size; in theory an implementation could have a "page" size of 1 byte. Similarly, reading zeros from the remainder of the page past the file size seems not to be specified. I could imagine some broken implementations leaking old file contents that were truncated here, but I would consider that a major security/privacy breach that would make such an implementation irrelevant in the real world. Of course they could fill the space with 0xDEADBEEF and then you'd be out of luck.

Even if you could assume zero-padding (which is probably the case for most real-world operating systems), I would caution against ever using it. What happens if your file happens to be an exact multiple of the system page size? Suddenly your code crashes reading past the end, or (perhaps worse) reads from an unrelated page that just happened to get mapped adjacent to your file's mapping. This is a very very nasty bug you'd probably fail to catch because the probability of having a text file that's an exact multiple of system page size is quite low.

绮筵 2024-10-09 05:33:46

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

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

The reason that you're seeing external updates to the file, even though it's mapped MAP_PRIVATE, is because you haven't written to the mapping so the system hasn't given you a private copy of the file pages yet. This behaviour is allowed but not required.

If you have your application modify contents[0] before the loop, it will not see the external changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文