为什么我们可以mmap到一个文件,但超过文件大小?

时间:2017-12-02 03:57:50

标签: c++ linux system-calls mmap

例如。

fd = ::open ("/test.txt", O_RDONLY, 0);
struct stat buf;
fstat(fd, &buf);
char* addr = (char*)::mmap(NULL, buf.st_size + 10, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);

请注意,我在此处映射了 + 10 。 但它仍然有效吗?

为什么系统不应用任何检查? 这有危险吗?

由于

2 个答案:

答案 0 :(得分:2)

mmap的签名是:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

引用Michael Kerrisk的话:

  

length参数指定映射的大小(以字节为单位)。   虽然长度不需要是系统页面大小的倍数   (由sysconf(_SC_PAGESIZE)返回),内核创建映射   这个尺寸的单位,实际上,长度是四舍五入到的   下一个页面大小的倍数。    - Linux编程接口(第49章)

引用Robert Love:

  

mmap()系统调用在页面上运行。 addr和offset参数都必须在页面大小的边界上对齐。也就是说,它们必须是页面大小的整数倍。因此,映射是页面的整数倍。如果调用者提供的len参数未在页面边界上对齐 - 可能是因为基础文件的大小不是页面大小的倍数 - 映射将向上舍入到下一个整页。此添加的内存中的最后一个有效字节和映射结束之间的字节为零填充。从该区域读取的任何内容都将返回零。对该内存的任何写入都不会影响后备文件,即使它被映射为MAP_SHARED。只有原始的len字节才会被写回文件。    - Linux系统编程(第4章)

答案 1 :(得分:1)

我假设您的系统正在运行Linux。请务必阅读intro(2)

我们可以mmap(2)超过其大小的文件,因为如果我们不能,只有具有页面大小的精确倍数的文件(通常为4K字节,可能是1M字节,请参见sysconf(3) {{1}可能是内存映射。如果是这种情况,内存映射文件将没那么有用。此外,PAGESIZE - ed文件的大小可能随时间而变化(其他进程write(2) - 并附加到它,调用ftruncate(2)等等...所以它不会感觉kernel要求(或强制执行)它不会改变。

仔细阅读mmap(2)的文档,它说:

  

文件以页面大小的倍数映射。对于一个文件   不是页面大小的倍数,剩余内存在归零时归零   映射,并写入该区域不会写入文件。

(当然内核正在做一些检查,可能比你想象的要多得多)

mmap可能会失败,因此您的代码应该检查,例如遵循它:

mmap
BTW,您的问题不是C ++特定的,而是POSIX或Linux特定的(其他操作系统可能不提供memory mapped files,或者可能对它们施加其他限制)。

请注意,内存映射非常常见。它由 if ((void*)addr == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); }; 使用,也在execve(2)时使用。您可以virtual address space mmap了解某些processusing(请参阅proc(5)并尝试/proc/cat /proc/self/maps终奌站)。 cat /proc/$$/maps经常被使用:malloc(3)mmapdlopen(3)ld-linux(8)关于动态链接的共享库。

另请阅读一些关于Linux或POSIX编程的书(例如旧版Advanced Linux Programming,可免费下载或更新版)和Operating Systems: Three Easy Pieces