6

I have a simple program going this:

int main(void) {
   int fd;
   const char *text = "This is a test";

   fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) );
   if ( fd < 0 ) {
           perror("open() error");
           return fd;
   }

    /* mmap the file. */
   void *address;
   off_t my_offset = 0;
   address = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, my_offset);

   if ( address == MAP_FAILED ) {
           perror("mmap error. " );
           return -1;
   }

    /* Move some data into the file using memory map. */
    strcpy( (char *)address, text);

    /* use msync to write changes to disk. */
    if ( msync( address, 4096 , MS_SYNC ) < 0 ) {
    perror("msync failed with error:");
        return -1;
    }
    else {
    printf("%s","msync completed successfully.");
}

    close(fd);
    unlink("/tmp/msyncTest");
}

Anything wrong with my code? I have made some simple tests and it seems that the problem comes from strcpy. But according to the definition, I see no problem.

Jens
  • 69,818
  • 15
  • 125
  • 179
HuangJie
  • 1,488
  • 1
  • 16
  • 33
  • 1
    You've not shown how `fd` is checked; how `len` and `my_offset` are set; how you check the `mmap()` call. We can guess that something associated with those caused the code to fail. – Jonathan Leffler Oct 29 '15 at 16:20
  • @JonathanLeffler Ok, I'll post all the code. – HuangJie Oct 29 '15 at 16:21
  • 1
    We only need to see an MCVE ([How to create a Minimal, Complete, and Verifiable Example?](http://stackoverflow.com/help/mcve)) — that could be another 10 lines or so. – Jonathan Leffler Oct 29 '15 at 16:22
  • 5
    If the file is newly created (as `O_CREAT` implies), it will be zero-sized. Accessing a part of a `mmap()`ed region that doesn't correspond to the underlying file (if any) causes sigbus. Solution: `ftruncate()` the file before `mmap()`. – EOF Oct 29 '15 at 16:28
  • @EOF Thanks buddy. That's the problem. – HuangJie Oct 29 '15 at 16:31
  • 2
    @EOF: You should make that an answer so the OP can accept it. I clicked on this question to answer it because it was unanswered, only to find that it already had an answer, but submitted as a comment rather than an answer. :-p – R.. GitHub STOP HELPING ICE Oct 29 '15 at 16:40
  • @R.. : You could always provide it as an answer and mark it as community wiki. That way a solution is posted but no one takes the credit. I came here too since it was unanswered. The question is a reasonable one IMHO. – Michael Petch Oct 29 '15 at 17:34
  • @MichaelPetch: Indeed, but I prefer the person who answered it get the credit/rep. – R.. GitHub STOP HELPING ICE Oct 30 '15 at 14:36

1 Answers1

7

If

fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) );

is successful, fd will refer to a zero-length file (O_TRUNC). The call to mmap()

address = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, my_offset);

establishes a memory-mapping, but the pages do not correspond to an object.

http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html has the following to say about this situation:

The system always zero-fills any partial page at the end of an object. Further, the system never writes out any modified portions of the last page of an object that are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object result in delivery of a SIGBUS signal.

Similarly, man mmap on Linux notes

Use of a mapped region can result in these signals:
[...]
SIGBUS Attempted access to a portion of the buffer that does not correspond to the file (for example, beyond the end of the file, including the case where another process has truncated the file).

Consequently, you must ftruncate() the file to a non-zero length before mmap()ing it (unless you are mmap()ing anonymous memory).

EOF
  • 6,273
  • 2
  • 26
  • 50
  • One detail: the `ftruncate` need not happen before the `mmap`; it can be done after the `mmap` as long as it takes place before any access that would fault. – R.. GitHub STOP HELPING ICE Oct 30 '15 at 04:26
  • 1
    @R.. I would *strongly* advise against that: http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html `If the size of the mapped file changes after the call to mmap() as a result of some other operation on the mapped file, the effect of references to portions of the mapped region that correspond to added or removed portions of the file is unspecified.` Linux `man mmap: The effect of changing the size of the underlying file of a mapping on the pages that correspond to added or removed regions of the file is unspecified.` – EOF Oct 30 '15 at 09:06