【问题标题】:got bus error when writing to mmap'ed file写入 mmap 文件时出现总线错误
【发布时间】:2017-07-21 18:25:33
【问题描述】:

尝试使用 mmap 写入文件。不幸的是,循环中的第一次写入map[i] = i; 将导致总线错误。不知道为什么。

PC 运行 Ubuntu 14.04,文件 /tmp/mmapped.bin 有 12 个字节,程序使用 ./a.out 3 调用。

谢谢

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

#define FILEPATH "/tmp/mmapped.bin"
//#define NUMINTS  (1000)
#define FILESIZE 0x400000000

int main(int argc, char *argv[])
{
    int i;
    int fd;
    int *map;  /* mmapped array of int's */
    int size = atoi(argv[1]);
    fd = open(FILEPATH, O_RDWR| O_CREAT | O_TRUNC);
    if (fd == -1) {
        perror("Error opening file for reading");
        exit(EXIT_FAILURE);
    }

    map = mmap(0, 4 * size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED) {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    for (i = 1; i <= size; ++i) {
        map[i] = i;
    }

    if (munmap(map, FILESIZE) == -1) {
        perror("Error un-mmapping the file");
    }
    close(fd);
    return 0;
}

【问题讨论】:

  • open(FILEPATH, O_RDWR| O_CREAT | O_TRUNC); 将您的文件截断为零长度。 mmap 不会为了创建映射而扩展文件;您需要在 mmap 之前自己扩展文件。此外,零长度映射是有效的,因此您不会遇到映射失败,但生成的映射中没有您有权写入的部分。
  • 感谢@twalberg 指出截断。我删除了标志O_TRUNC(重新编译)并确保文件有12个字节,./a.out 3仍然给出了总线错误。
  • 另外,由于您将map 声明为int *map[3] 可能是文件中的 12 个字节(32 位 int)或文件中的 24 个字节(64 位)。在任何一种情况下,它都超出了 12 字节文件的结尾...尝试unsigned char *map;...
  • 有趣的是,它在执行map[0] = 0时导致崩溃。
  • 另一个问题是您尝试munmap 一个比您mmap 大得多的区域。当我在mmap 之前插入ftruncate 调用以确保文件足够大,并修复munmap 调用时,我不再遇到失败...

标签: c linux mmap


【解决方案1】:

在 c 中,您需要从索引 0 开始。因为它只会将指针增加 i 的数量,然后取消引用它。您的代码取消引用超出允许范围的指针。

应该是,

for (i = 0; i < size; ++i) {
    map[i] = i;
}

因为它相当于

for (i = 0; i < size; ++i) {
    *(map + i) = i;
}

另外,使用

map = mmap(0, size * sizeof *map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

确保分配了足够的空间并且*(map + i) 将在边界内。不要使用幻数。

【讨论】:

  • 你说得对,它应该以i=0 开头,但它不应该在i=1 时崩溃。我进行了更改,但它仍然因总线错误而崩溃。
【解决方案2】:

根据mmap man page,当您在文件边界之外读取/写入时会发生总线错误 (SIGBUS)。

映射的长度与文件的长度是分开的。如果您的文件是新创建的,它的大小将为 0,即使您使用 mmap 指定长度也是如此。打开后用ftruncate调整文件大小。

【讨论】:

  • 感谢@matthew-marshall 提供ftruncate 的提示。就我而言,我有一个 12 个字节的文件,我只想覆盖前 4 个字节。知道为什么它不起作用吗?
猜你喜欢
  • 2014-05-12
  • 2014-05-20
  • 2016-01-29
  • 1970-01-01
  • 2017-02-17
  • 2015-11-13
  • 1970-01-01
  • 1970-01-01
  • 2018-02-18
相关资源
最近更新 更多