15年前的mmap教程运行异常,是教程错误还是GCC编译问题?
问题根源
这是教程代码本身存在的数组越界访问bug,具体原因如下:
- 代码中定义
NUMINTS=1000,内存映射的区域总大小是1000 * sizeof(int),对应int类型数组的合法下标范围是0 ~ 999,但读写代码的循环均写为for (i = 1; i <=NUMINTS; ++i),直接访问了map[1000]这个越界地址,属于C语言标准规定的未定义行为,不同运行场景下结果不一致是正常表现。 - 两种运行结果的差异是Linux文件系统、内存管理的特性共同导致的:
- 当
/tmp/mmapped.bin不存在时,新建文件的磁盘块、对应的内存映射页均为全新分配,越界的map[1000]刚好落在映射区后未被占用的匿名内存页上,写入的2000暂时保存在该页中,读取时就能拿到对应值。 - 当文件预先存在时,
open指定的O_TRUNC标志会清空原有文件内容,旧的磁盘块被系统回收并清零,扩充文件大小后映射的内存边界刚好卡在map[999]的末尾,越界写入的2000不会同步到文件中,读取时就拿到了对应位置的初始0值。
- 当
修复方法
调整循环的下标范围,避免越界访问即可,参考修改如下:
// mmap_write.c 写入循环修改 for (i = 0; i < NUMINTS; ++i) { map[i] = 2 * (i + 1); } // mmap_read.c 读取循环修改 for (i = 0; i < NUMINTS; ++i) { printf("%d: %d\n", i + 1, map[i]); }
内容的提问来源于stack exchange,提问作者MWB
相关产品推荐
相关产品推荐

