mmap文件映射bus error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, char** argv)
{
    int fd;
    int* shm_ptr;
    if (argc != 2) {
        std::clog << "Usage: " 
            << argv[0] << " file" 
            << std::endl;
        return -1;
    }
    if ((fd = open(argv[1], O_RDWR | O_CREAT, 0666)) < 0) {
        std::clog << "open failed, " 
            <<  strerror(errno) << std::endl;
        return -1;
    }
    shm_ptr = (int*)mmap(NULL, sizeof(int), 
            PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == shm_ptr) {
        std::clog << "mmap failed, " 
            << strerror(errno) << std::endl;
        return -1;
    }

    *shm_ptr = 0;

    return 0;
}

执行到第31行时出现“bus error”。

mmap过后,tmp文件并不会被立即调入物理内存。文件会被分成n个与虚拟内存页面同尺寸的块(页面),当发生内存(映射了tmp文件的内存区)读写操作的时候,CPU会先明确此次操作落在哪个页面上。然后查询页表,确定这个页面是否存在于物理内存之中,如果不在,则触发缺页中断,将这个页面从tmp文件载入到物理内存。

问题在于被映射的文件“tmp”是在open的时候被创建的,它是一个空文件。空文件就是size为0,size为0就是没有页面对应到映射内存区域。当实际要载入物理内存的时候就引发了SIGSEGV信号,shell解释即为“bus error”。

其实就是这个tmp文件按页面大小进行切分之后,得到的页面数目比映射内存区的页面数目少。而此时,要是操作那些在映射内存区有,而tmp文件中没有的页面的话,就出现了这个错误。 处理办法是:在操作映射内存区的时候不要访问红色的区域,要么就增加文件的size,让其切出的page个数与映射内存区的page相匹配。