为什么mremap只访问4096字节的内存后?

时间:2018-12-01 14:24:13

标签: linux virtual-memory

下面的代码以mmap(initlen = 10)开始,稍后重新映射(nsize = 400000),并访问重新映射内存地址 可以访问0x7ffff7f8c000到0x7ffff7f8cfff,但是在0x7ffff7f8d000中会导致访问错误

DF <- data.frame(year = "1_1_1_1_LT05_127024_19870517_00005ff8aac6b6bf60bc",
 stringsAsFactors = FALSE)

gdb之后的mremap显示“ /tmp/task.0”区域为0x7ffff7f8c000-0x7ffff7fee000,访问错误为0x7ffff7f8d000,为什么?

#define _GNU_SOURCE
#include <stdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>


int main()
{
    int i;
    char *p;
    void *base;
    const int initlen = 10;
    const int nsize = 400000;

    const char *fname = "/tmp/task.0";
    int fd = open(fname, O_CREAT|O_RDWR, 0600);
    if (fd == -1) {
        return 1;
    }

    if (ftruncate(fd, initlen) < 0) {
        return 1;
    }

    base = mmap(NULL, initlen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (base == MAP_FAILED) {
        return 1;
    }

    // now remap big page.
    base = mremap(base, initlen, nsize, MREMAP_MAYMOVE);
    if (base == MAP_FAILED) {
        printf("mremap fail, %s\n", strerror(errno));
        return 1;
    }

    p = base;
    for (i = 0; i < nsize; i++) {
        printf("%p\n", p);
        *p = i % CHAR_MAX;
        ++p;
    }

    return 0;
}

1 个答案:

答案 0 :(得分:1)

它与mremap不相关。这就是文件映射的工作方式。 SIGBUS意味着您试图访问超出其EOF的文件区域(请参见手册页mmap(3))。

  

SIGBUS尝试访问与文件不对应的缓冲区部分(例如,超出文件末尾,包括其他进程已截断文件的情况)。

这与SIGSEGV不同,SIGSEGV在您尝试访问进程中不存在的虚拟地址或发生保护错误(例如,尝试写入只读地址)时发送。

要回答这个问题,为什么不获得SIGBUS就可以访问第一个0xfff字节(即使文件大小只有10个字节),这是因为内存管理是根据4096字节的页面进行的。但是请注意,即使您可以访问字节10..4095,该区域也不受文件支持。您写入这些字节的所有内容都不会写入文件。