关闭文件描述符后没有调用munmap(),mmap()指针的行为是什么?

5

Consider the following code fragment:

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

int fd = open( "/path/to/existing/file/or/device", O_RDONLY);
int numberOfWords = 4096; // chosen to be smaller than file size
int* data = mmap( NULL, nomberOfWords * sizeof(int), PROT_READ, MAP_SHARED, fd, 0); 
if (data != MAP_FAILED) {

   printf( "%d\n", data[0]);

   // oops, forgot to munmap

   close(fd);

   printf( "%d\n", data[0]);        // <-- why doesn't this segfault

}

背景

我正在使用一个定制的内核驱动程序,该程序使用ioctl()设置DMA,并最终需要用户空间使用mmap()来访问特定的缓冲区。

在编写单元测试时,我无意中发现在关闭文件描述符之前没有调用munmap的情况下,仍然可以使用mmap'ed指针在用户空间中访问缓冲区内存。考虑到驱动程序可能存在某些错误,我编写了一个类似于此处示例的小程序来使用“正常”文件运行mmap()。

我原本期望的是,在关闭后读取会导致段错误,我的想法是当打开文件描述符的使用被关闭时,内核会自动munmap()与文件描述符相关联的页面,就像在进程终止时发生的那样。

但实际上,我仍然能够继续使用指针。这有点令人惊讶,因为我使用mmap()已经几年了,我肯定足够聪明(更可能是幸运)以避免暴露出这种情况的错误。在mmap手册页中没有明显的提示。

问题

理想情况下,我们的驱动程序将需要在用户空间中引发段错误,如果发生这种情况,因为我们不希望有错误的用户空间程序写入感兴趣的内存。

那么,在不同的*nix系统中,这种行为是否相同?在给定的示例中,删除文件会导致段错误吗?或者刷新vm缓存会起作用吗?

2个回答

11

好的,在撰写了大部分问题后,我发现了这个不同的问题,其措辞与我一开始搜索时有所不同: 在调用mmap后,我需要保持文件打开吗?

回答引用了POSIX手册,事实证明在man页面中有解释(在munmap下,顺便提一句 :-| ),关闭描述符将不会自动取消映射。因此,看起来我们需要修改驱动程序关闭代码以使相关内存映射无效,这样用户空间就会出现段错误。

我决定发布这个问题,以防其他人搜索类似的内容。


2
如果驱动程序仅仅因为文件被关闭就使内存映射无效,那么这是错误的。事实上,mmap 的文档说明了在文件关闭后仍然可以继续使用内存映射区域。当映射实际消失以及每个文件描述符关闭时,你的驱动程序应该从内核核心获得通知。 - zwol

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接