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

捕获SIGSEGV后调用mmap映射内存失败,报错Cannot allocate memory

问题分析与解决方案

核心问题原因

在macOS上,你的代码触发mmap返回Cannot allocate memory错误,主要源于以下几点:

1. 信号处理函数注册方式错误

你用signal()注册处理函数,但该函数不支持传递siginfo_t扩展信息,会导致信号处理函数内的si指针无效。更关键的是,这种老旧接口无法保证信号处理的可靠性,间接影响后续内存映射操作。

2. MAP_FIXED的地址冲突问题

MAP_FIXED要求指定地址必须是进程虚拟空间中完全未被占用的页对齐区域。你选择的page_size*100(通常是409600)属于低地址范围,macOS会将这类区域保留给系统或进程的初始内存段,强制映射必然失败。

3. 信号上下文的内存分配限制

尽管mmap属于POSIX定义的异步信号安全函数,但在信号处理的上下文里执行内存映射,可能受进程当前状态限制,增加分配失败概率。

修复后的代码

#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>

void *addr;

static void catch_function(int signo, siginfo_t *si, void *unused) {
    printf("Got SIGSEGV at address: 0x%lx\n", (unsigned long)si->si_addr);

    // 改用页对齐的映射长度,选择高地址区域尝试映射
    void *ptr = mmap(addr, getpagesize(), PROT_READ | PROT_WRITE,
                     MAP_SHARED | MAP_ANON | MAP_FIXED, -1, 0);

    if (ptr == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    } else {
        printf("mmap succeeded at address: 0x%lx\n", (unsigned long)ptr);
    }
}

int main(void) {
    int page_size = getpagesize();
    struct sigaction sa;

    // 用sigaction注册支持扩展信息的信号处理函数
    sa.sa_sigaction = catch_function;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGSEGV, &sa, NULL) == -1) {
        fputs("Failed to set signal handler.\n", stderr);
        return EXIT_FAILURE;
    }

    // 选择64位macOS中更可能可用的高地址区域
    addr = (void *)(0x100000000UL);

    // 触发段错误
    *((int *)addr) = 1;

    printf("Successfully wrote to address: 0x%lx\n", (unsigned long)addr);
    return EXIT_SUCCESS;
}

关键修复点

  • 替换signal()为sigaction():保证能正确获取段错误的地址信息,同时遵循现代信号处理的标准规范。
  • 调整目标地址:选择0x100000000这类64位系统的高地址区域,避开系统保留的低地址段,降低冲突概率。
  • 规范映射长度:mmap的长度参数必须是页大小的整数倍,显式使用getpagesize()避免系统自动取整带来的潜在问题。
  • 可选:移除MAP_FIXED:如果不需要强制映射到指定地址,去掉该标志可让系统自动分配可用地址,彻底避免地址冲突问题。若必须用MAP_FIXED,可通过vmmap <pid>命令查看进程当前地址布局,确认目标区域未被占用。

额外说明

即使mmap成功,触发段错误的指令会在信号处理完成后重新执行,此时地址已被映射,就能正常写入。但这种方式仅适用于简单的内存缺失场景,生产环境中不建议依赖信号处理动态修复内存访问问题,逻辑复杂时容易引发死循环或其他不可控问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 05:12:43