简体   繁体   English

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

[英]Why does a read operation on a memory mapped zero byte file lead to SIGBUS?

Here is the example code I wrote. 这是我写的示例代码。

#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;
}

If I provide a zero byte foo.txt to this program, it terminates with SIGBUS. 如果我向该程序提供零字节foo.txt,它将以SIGBUS终止。

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

If I provide a one byte foo.txt to this program, then there is no such issue. 如果我为这个程序提供一个字节的foo.txt,那么就没有这样的问题了。

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

mmap(2) mentions the following. mmap(2)提到以下内容。

Use of a mapped region can result in these signals: 使用映射区域可能会产生以下信号:

SIGSEGV Attempted write into a region mapped as read-only. SIGSEGV尝试写入映射为只读的区域。

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). SIGBUS尝试访问与文件不对应的缓冲区的一部分(例如,超出文件末尾,包括另一个进程截断文件的情况)。

So if I understand this correctly, even the second test case (1-byte file) should have led to SIGBUS because data[1] and data[2] are trying to access a portion of the buffer ( data ) that does not correspond to the file. 因此,如果我理解正确,即使第二个测试用例(1字节文件)应该导致SIGBUS,因为data[1]data[2]试图访问不对应的缓冲区( data )的一部分文件。

Can you help me understand why only a zero byte file causes this program to fail with SIGBUS? 你能帮助我理解为什么只有一个零字节文件导致这个程序失败并使用SIGBUS吗?

You get SIGBUS when accessing past the end of last whole mapped page because the POSIX standard states : 当访问过去整个映射页面的末尾时,您会收到SIGBUS ,因为POSIX标准指出

The mmap() function can be used to map a region of memory that is larger than the current size of the object. mmap()函数可用于映射大于对象当前大小的内存区域。 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信号被发送到进程。

With a zero-byte file, the entire page you mapped is "beyond the current end of the underlying object". 使用零字节文件,您映射的整个页面“超出了底层对象的当前末尾”。 So you get SIGBUS . 所以你得到了SIGBUS

You do NOT get a SIGBUS when you go beyond the 4kB page you've mapped because that's not within your mapping. 当你超越你绘制的4kB页面时,你不会得到一个SIGBUS ,因为那不在你的映射中。 You don't get a SIGBUS accessing your mapping when your file is larger than zero bytes because the entire page gets mapped. 当文件大于零字节时,您不会获得SIGBUS访问映射,因为整个页面都已映射。

But you would get a SIGBUS if you mapped additional pages past the end of the file, such as mapping two 4kB pages for a 1-byte file. 但是,如果您将其他页面映射到文件末尾,则会得到一个SIGBUS ,例如为一个1字节的文件映射两个 4kB页面。 If you access that second 4kB page, you'd get SIGBUS . 如果您访问第二个4kB页面,您将获得SIGBUS

A 1-byte file does not lead to the crash because mmap will map memory in multiples of the page size and zero the remainder. 1字节文件不会导致崩溃,因为mmap将以页面大小的倍数映射内存,并将剩余部分归零。 From the man page: 从手册页:

A file is mapped in multiples of the page size. 文件以页面大小的倍数映射。 For a file that is not a multiple of the page size, the remaining memory is zeroed when mapped, and writes to that region are not written out to the file. 对于不是页面大小倍数的文件,剩余内存在映射时归零,并且写入该区域不会写入文件。 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. 未指定更改对应于文件的添加或移除区域的页面上的映射的基础文件的大小的效果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM