sanjoyd
sanjoyd

Reputation: 3340

Memory Mapped files on a POSIX system kept in sync

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?

Upvotes: 1

Views: 557

Answers (3)

caf
caf

Reputation: 239041

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.

Upvotes: 0

Jens Gustedt
Jens Gustedt

Reputation: 78903

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.

Upvotes: 2

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215259

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.

Upvotes: 1

Related Questions