You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

mmap调用使用MAP_FIXED时报Invalid argument错误的解决方法

问题背景

运行环境:Ubuntu 16.04,内核版本4.17.4
编写共享内存相关代码时,尝试将进程地址空间映射到创建的共享内存区域,在mmap()调用中使用MAP_FIXED标志时,程序返回如下错误:

mmap: Invalid argument

完整问题代码如下:

#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define STORAGE_ID "/SHM_TEST"
#define STORAGE_SIZE 4096

int main(int argc, char *argv[])
{
    int res, temp;
    int fd;
    int len;
    pid_t pid;
    void *addr;
    char data[STORAGE_SIZE];

    fd = shm_open(STORAGE_ID, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd == -1)
    {
        perror("open");
        return 10;
    }

    res = ftruncate(fd, STORAGE_SIZE);
    if (res == -1)
    {
        perror("ftruncate");
        return 20;
    }

    addr = mmap(NULL, STORAGE_SIZE, PROT_WRITE, MAP_FIXED, fd, 0);

    if (addr == MAP_FAILED)
    {
        perror("mmap");
        return 30;
    }

    res = munmap(addr, STORAGE_SIZE);
    if (res == -1)
    {
        perror("munmap");
        return 40;
    }

    // shm_open cleanup
    fd = shm_unlink(STORAGE_ID);
    if (fd == -1)
    {
        perror("unlink");
        return 100;
    }

    return 0;
}

使用MAP_FIXED标志的原因是后续需要手动指定映射地址,而非传入NULL参数(尝试传入手动指定的地址时仍然出现相同错误),需要如何操作才能正确在mmap()调用中使用MAP_FIXED标志?

错误原因

你遇到的报错来自两个核心问题:

  • MAP_FIXED标志使用规则违反:当传入MAP_FIXED时,mmap的第一个参数addr不能为NULL,同时传入的地址必须满足页对齐要求(地址值为系统内存页大小的整数倍),且对应的虚拟地址区间属于进程可用地址范围,否则内核会直接返回EINVAL(也就是Invalid argument错误)。你当前代码直接给MAP_FIXED传NULL作为地址,是触发报错的直接原因。
  • 缺少必要的映射标志:共享内存映射必须搭配MAP_SHARED标志,否则映射的是内存私有副本,完全达不到共享内存的通信目的,属于隐性逻辑错误。
正确使用MAP_FIXED的方法

不要硬编码固定地址(受ASLR地址空间随机化影响,硬编码地址在不同进程、不同运行环境下几乎必然非法),按照以下步骤操作:

  • 第一步:先获取系统页大小,可通过sysconf(_SC_PAGESIZE)获取,你的环境下默认值为4096字节。
  • 第二步:先向内核申请一块空闲、页对齐的预留地址区间,避免手动指定的地址已经被代码段、堆、栈或其他映射区域占用。
  • 第三步:拿到合法的预留地址后,再搭配MAP_FIXED和MAP_SHARED标志映射共享内存到该地址。
  • 可选安全优化:你的4.17版本内核支持MAP_FIXED_NOREPLACE标志,相比强制覆盖原有映射的MAP_FIXED,该标志在目标地址已被占用时会直接返回错误,不会破坏进程原有内存映射,稳定性更高。
修正后的核心代码片段
#include <unistd.h> // 引入sysconf对应的头文件

// ... 前面的shm_open、ftruncate逻辑不变 ...

long page_size = sysconf(_SC_PAGESIZE);
// 先预留一块空闲的合法地址
void *target_addr = mmap(NULL, STORAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (target_addr == MAP_FAILED) {
    perror("reserve address");
    return 25;
}
// 释放预留地址,该地址短时间内不会被内核分配给其他映射
munmap(target_addr, STORAGE_SIZE);

// 带MAP_FIXED映射共享内存,注意必须加MAP_SHARED
addr = mmap(target_addr, STORAGE_SIZE, PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
if (addr == MAP_FAILED)
{
    perror("mmap");
    return 30;
}

// ... 后续逻辑不变 ...

内容的提问来源于stack exchange,提问作者Misbah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 21:31:10