c - 为什么对内存映射零字节文件的读取操作会导致 SIGBUS?

标签 c mmap sigbus

这是我写的示例代码。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main()
{
    int fd;
    long pagesize;
    char *data;

    if ((fd = open("foo.txt", O_RDONLY)) == -1) {
        perror("open");
        return 1;
    }

    pagesize = sysconf(_SC_PAGESIZE);
    printf("pagesize: %ld\n", pagesize);

    data = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0);
    printf("data: %p\n", data);
    if (data == (void *) -1) {
        perror("mmap");
        return 1;
    }

    printf("%d\n", data[0]);
    printf("%d\n", data[1]);
    printf("%d\n", data[2]);
    printf("%d\n", data[4096]);
    printf("%d\n", data[4097]);
    printf("%d\n", data[4098]);

    return 0;
}

如果我向该程序提供零字节 foo.txt,它会以 SIGBUS 终止。

$ > foo.txt && gcc foo.c && ./a.out 
pagesize: 4096
data: 0x7f8d882ab000
Bus error

如果我给这个程序提供一个字节的foo.txt,就没有这个问题。

$ printf A > foo.txt && gcc foo.c && ./a.out 
pagesize: 4096
data: 0x7f5f3b679000
65
0
0
48
56
10

mmap(2)提到以下内容。

Use of a mapped region can result in these signals:

SIGSEGV Attempted write into a region mapped as read-only.

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).

因此,如果我理解正确,即使是第二个测试用例(1 字节文件)也应该导致 SIGBUS,因为 data[1]data[2]正在尝试访问与文件不对应的缓冲区部分 (data)。

你能帮我理解为什么只有一个零字节文件会导致这个程序因 SIGBUS 而失败吗?

最佳答案

当访问超过最后一个完整映射页面的末尾时,您会得到 SIGBUS,因为 the POSIX standard states :

The mmap() function can be used to map a region of memory that is larger than the current size of the object. Memory access within the mapping but beyond the current end of the underlying objects may result in SIGBUS signals being sent to the process.

对于零字节文件,您映射的整个页面“超出了底层对象的当前端”。所以你得到 SIGBUS

当您超出已映射的 4kB 页面时,您不会得到 SIGBUS,因为那不在您的映射范围内。当您的文件大于零字节时,您不会得到 SIGBUS 访问您的映射,因为整个页面都被映射了。

但是如果您映射文件末尾之后的其他页面,例如为一个 1 字节文件映射两个 4kB 页面,您将得到一个SIGBUS。如果您访问第二个 4kB 页面,您将获得 SIGBUS

关于c - 为什么对内存映射零字节文件的读取操作会导致 SIGBUS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41416028/

相关文章:

c - 程序执行是否总是从 C 中的 main 开始?

c++ - 在同一行上使用 malloc 创建两个数组

c - 为什么 mmap() 比顺序 IO 快?

c - GCC 4.0.2 取消引用指向结构的双类型成员的指针会引发 SIGBUS 错误

c - OpenSC 与 openCryptoKI

c++ - 通过 Mmap-ed 共享内存传递可变长度的 C 字符串

embedded - 通过/dev/mem驱动Beaglebone GPIO

java - Android 致命信号 7 (SIGBUS)

c++ - 如何正确处理 SIGBUS 以便我可以继续搜索地址?

c - Linux TCP 服务器 : reading client's IP address before accepting connection