如何使用 mmap() 确定是否所有映射页面都有效?

How can I determine if all mapped pages while using mmap() are valid?

提问人:user16217248 提问时间:6/17/2023 最后编辑:user16217248 更新时间:6/17/2023 访问量:109

问:

我了解到,即使调用返回成功,分配的页面也可能不可用。例如,如果正在映射一个文件,并且传递给 mmap()len 足够大于该文件。在这种情况下,超出文件使用的页面的任何页面,即使在请求的大小内,如果尝试使用它们,也会产生一个。mmap()SIGBUS

有没有办法直接确定从映射开始到的所有字节是否可以安全访问?除了手动测量文件的长度,或设置处理程序,或以其他方式(详尽地)检查是否满足页面无法访问的任何原因之外,我还可以这样做吗?lenSIGBUS

// Assuming PAGE_SIZE == 4096
int fd = open("file", O_RDONLY);
void *buffer = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0);
// Is there any way to determine if reading bytes 4093-8192 will cause a bus error?
// Besides measuring if the size of the file is greater than 4092?

我是否可以直接确定是否有任何页面因任何原因不可用,而不是检查文件大小以确定是否有任何页面因文件太小而不可用?

C 内存 错误处理 POSIX mmap

评论

3赞 Craig Estey 6/17/2023
用于获取文件的大小。然后,用于增大/缩小文件。然后,执行 .fstatftruncatemmap
1赞 Andrew Henle 6/17/2023
@user16217248 测量文件大小有什么问题?您已经有一个打开的文件描述符,并且与系统执行实际映射然后分页文件数据所需的内存映射回转所需的时间相比,对已经缓存的文件元数据进行一次额外访问以获取长度实际上是无法测量的。
0赞 user16217248 6/17/2023
@AndrewHenle 所以规范的方法是单独检查文件是否足够大?
0赞 Andrew Henle 6/17/2023
@user16217248差不多。如果您使用的是 Linux,请运行类似 .你将看到运行时链接器通过一堆 // 调用加载可执行文件所需的所有库。strace -o /tmp/out.txt lslsopen()fstat()mmap()

答:

0赞 user16217248 6/17/2023 #1

规范的方法是无论如何都只用于测量文件的大小,如果文件太小,则失败。没有更“直接”的方法来查询页面的可用性,也不需要这样的方法,因为手册页Signals 下显示,唯一的方法是文件太小:fstat()SIGBUS

SIGBUS Attempted access to a page of the buffer that lies beyond
      the end of the mapped file.  For an explanation of the
      treatment of the bytes in the page that corresponds to the
      end of a mapped file that is not a multiple of the page
      size, see NOTES.

以下代码是如何安全使用的示例:mmap()

#define PAGE_ALIGN(S) ((S)+PAGE_SIZE-1&~(PAGE_SIZE-1))
#define EXPECTED_SIZE /* ... */

int fd = open("file", O_RDONLY);
struct stat statbuf;
if (fstat(fd, &statbuf) || PAGE_ALIGN(statbuf.st_size) < EXPECTED_SIZE)
    return EXIT_FAILURE;
void *mapping = mmap(NULL, EXPECTED_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (mapping == MAP_FAILED)
    return EXIT_FAILURE;