Bus error (core dumped) when using strcpy to a mmap'ed file
Asked Answered
S

1

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.

Somatist answered 29/10, 2015 at 16:18 Comment(8)
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.Leanoraleant
@JonathanLeffler Ok, I'll post all the code.Somatist
We only need to see an MCVE (How to create a Minimal, Complete, and Verifiable Example?) — that could be another 10 lines or so.Leanoraleant
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().Incorruptible
@EOF Thanks buddy. That's the problem.Somatist
@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. :-pGallon
@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.Gospel
@MichaelPetch: Indeed, but I prefer the person who answered it get the credit/rep.Gallon
I
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).

Incorruptible answered 29/10, 2015 at 18:33 Comment(2)
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.Gallon
@R.. I would strongly advise against that: 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.Incorruptible

© 2022 - 2024 — McMap. All rights reserved.