下面的代码以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;
}
答案 0 :(得分:1)
它与mremap
不相关。这就是文件映射的工作方式。
SIGBUS意味着您试图访问超出其EOF的文件区域(请参见手册页mmap(3))。
SIGBUS尝试访问与文件不对应的缓冲区部分(例如,超出文件末尾,包括其他进程已截断文件的情况)。
这与SIGSEGV不同,SIGSEGV在您尝试访问进程中不存在的虚拟地址或发生保护错误(例如,尝试写入只读地址)时发送。
要回答这个问题,为什么不获得SIGBUS就可以访问第一个0xfff字节(即使文件大小只有10个字节),这是因为内存管理是根据4096字节的页面进行的。但是请注意,即使您可以访问字节10..4095,该区域也不受文件支持。您写入这些字节的所有内容都不会写入文件。