将strcpy用于mmap时出现总线错误(堆芯转储)';ed文件

将strcpy用于mmap时出现总线错误(堆芯转储)';ed文件,c,strcpy,C,Strcpy,我有一个简单的程序: int main(void) { int fd; const char *text = "This is a test"; fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) ); if ( fd < 0 ) { perror("open() error"); return f

我有一个简单的程序:

int main(void) {
   int fd;
   const char *text = "This is a test";

   fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) );
   if ( fd < 0 ) {
           perror("open() error");
           return fd;
   }

    /* mmap the file. */
   void *address;
   off_t my_offset = 0;
   address = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, my_offset);

   if ( address == MAP_FAILED ) {
           perror("mmap error. " );
           return -1;
   }

    /* Move some data into the file using memory map. */
    strcpy( (char *)address, text);

    /* use msync to write changes to disk. */
    if ( msync( address, 4096 , MS_SYNC ) < 0 ) {
    perror("msync failed with error:");
        return -1;
    }
    else {
    printf("%s","msync completed successfully.");
}

    close(fd);
    unlink("/tmp/msyncTest");
}
int main(无效){
int-fd;
const char*text=“这是一个测试”;
fd=开放(“/tmp/msyncTest”),(O|u CREAT | O|u TRUNC | O|u RDWR),(S|IRWXU | S|IRWXG | S|IRWXO));
如果(fd<0){
perror(“open()错误”);
返回fd;
}
/*mmap文件*/
无效*地址;
off\u t my\u offset=0;
地址=mmap(空,4096,保护写入,映射共享,fd,我的偏移量);
如果(地址==映射_失败){
perror(“mmap错误”);
返回-1;
}
/*使用内存映射将一些数据移动到文件中*/
strcpy((char*)地址,文本);
/*使用msync将更改写入磁盘*/
if(msync(地址,4096,MS_SYNC)<0){
perror(“msync失败,错误:”);
返回-1;
}
否则{
printf(“%s”,“msync已成功完成”);
}
关闭(fd);
取消链接(“/tmp/msyncTest”);
}
我的代码有问题吗?我做了一些简单的测试,问题似乎来自于strcpy。但是根据定义,我看没有问题。

如果

fd = open("/tmp/msyncTest", (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO) );
如果成功,
fd
将引用零长度文件(
O_TRUNC
)。调用
mmap()

建立内存映射,但页与对象不对应

关于这种情况有以下几点要说:

系统始终为零填充对象末尾的任何部分页面。此外,系统从不写出对象最后一页超出其末尾的任何修改部分。地址范围内的引用从pa开始,并在对象结束后的整个页面上持续len字节,导致SIGBUS信号的传递

类似地,Linux notes上的
manmmap

使用映射区域可能会产生以下信号:
[…]
SIGBUS试图访问缓冲区中与文件不对应的部分(例如,超出文件末尾,包括另一个进程已截断文件的情况)


因此,您必须
ftruncate();如何设置
len
my_offset
;如何检查
mmap()
调用。我们可以猜到与这些相关的东西导致了代码失败。@JonathanLeffler好的,我将发布所有代码。我们只需要看到一个MCVE()-可能是另外10行左右。如果文件是新创建的(正如
O_create
所暗示的那样),它的大小将为零。访问与基础文件(如果有)不对应的
mmap()
ed区域的一部分会导致sigbus。解决方案:
ftruncate()
前面的文件
mmap()
@EOF:您应该回答这个问题,以便OP可以接受它。我点击这个问题来回答它,因为它没有回答,结果发现它已经有了答案,但它是作为评论而不是答案提交的-pOne详细信息:
ftruncate
无需在
mmap
之前发生;它可以在
mmap
之后完成,只要它发生在任何可能出现故障的访问之前。@R。。我强烈建议不要这样做:
如果在调用mmap()后,由于对映射文件执行了其他操作,映射文件的大小发生了变化,未指定引用与文件的添加或删除部分相对应的映射区域部分的效果。
Linux
man mmap:在与文件的添加或删除区域相对应的页面上更改映射的基础文件大小的效果未指定。
address = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, my_offset);