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

Linux多进程C程序偶发malloc sysmalloc断言错误排查求助

malloc断言失败问题排查(Linux多进程C程序)

我在Linux环境下编写了一个使用消息队列和信号的多进程C程序,终端偶尔会弹出以下错误:

scheduler.out: malloc.c:2617: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.

错误通常出现在信号处理函数receiveProcess第3或第4次调用时,并非每次触发。


相关代码

Process结构体定义

typedef struct Process {
    int id;
    int pid;
    int arrival;
    int startTime;
    int runtime;
    int priority;
    int WaitingTime;
    int remainingTime;
    char state[20];
    int Sent;
} Process;

核心函数实现

Process* stringtoProcess(char* str) {
    Process* p = malloc(sizeof(Process));
    sscanf(str, "%d %d %d %d %d %d %d %s", &p->id, &p->arrival, &p->startTime, &p->runtime, &p->priority, &p->WaitingTime, &p->remainingTime, p->state);
    return p;
}

void receiveProcess() {
    key_t key_up, key_down;
    int msgid_up, msgid_down;
    struct msgbuf buffer_up, buffer_down;
    key_up = ftok("keyfile", 'A');
    key_down = ftok("keyfile", 'Z');
    if (key_up == -1 || key_down == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    msgid_up = msgget(key_up, 0666 | IPC_CREAT);
    msgid_down = msgget(key_down, 0666 | IPC_CREAT);
    if (msgid_up == -1 || msgid_down == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }
    memset(&buffer_up, 0, sizeof(buffer_up));
    memset(&buffer_down, 0, sizeof(buffer_down));
    if (msgrcv(msgid_up, &buffer_up, sizeof(buffer_up.mtext), 5, !IPC_NOWAIT) == -1) {
        perror("msgrcv");
        exit(EXIT_FAILURE);
    }
    Process *p = stringtoProcess(buffer_up.mtext);
    TotalRunTime += p->runtime;
    if(FirstArrival == -1)
    FirstArrival = p->arrival;
    if(algo == 1)
        enqueue(ready_queue, p);
    else push(ready_queue, p, prio_flag);
    buffer_down.mtype = 5;
    if(msgsnd(msgid_down, &buffer_down, sizeof(buffer_down.mtext), 5) == -1) {
        perror("msgsend");
        exit(EXIT_FAILURE);
    }
}

问题根源分析

这个malloc断言失败本质是堆内存被破坏,结合你的场景,核心诱因有以下几点:

  • 信号处理函数调用异步不安全函数:malloc、sscanf、msgrcv均属于异步信号不安全函数,在信号处理流程中调用会打断主进程的堆操作逻辑,直接引发堆 corruption。
  • sscanf越界写入:如果消息队列中state字段的字符串长度超过19(state数组长度20,需留1字节存终止符),会越界覆盖Process结构体后的堆内存,破坏堆结构。
  • 全局变量无保护访问:TotalRunTime、FirstArrival、ready_queue这些全局变量在信号处理中直接修改,无同步机制,多信号触发时会产生竞态,破坏数据结构或堆内存。

修复建议

  1. 重构信号处理逻辑:信号处理函数只做最小化操作,比如设置一个全局原子标志,主进程循环检测标志后再执行消息接收、内存分配等安全操作,避免在信号回调中调用异步不安全函数。
  2. 限制sscanf写入长度:修改sscanf格式串,给state字段加长度限制,防止越界:
    sscanf(str, "%d %d %d %d %d %d %d %19s", &p->id, &p->arrival, &p->startTime, &p->runtime, &p->priority, &p->WaitingTime, &p->remainingTime, p->state);
    
  3. 保护全局变量:对全局变量的读写使用原子操作(如stdatomic.h中的接口),或在主进程操作时加互斥锁(注意互斥锁在信号处理中需谨慎使用,优先原子操作)。
  4. 校验消息数据合法性:调用stringtoProcess前,先检查buffer_up.mtext的格式和长度,过滤非法数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:53:17