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这些全局变量在信号处理中直接修改,无同步机制,多信号触发时会产生竞态,破坏数据结构或堆内存。
修复建议
- 重构信号处理逻辑:信号处理函数只做最小化操作,比如设置一个全局原子标志,主进程循环检测标志后再执行消息接收、内存分配等安全操作,避免在信号回调中调用异步不安全函数。
- 限制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); - 保护全局变量:对全局变量的读写使用原子操作(如
stdatomic.h中的接口),或在主进程操作时加互斥锁(注意互斥锁在信号处理中需谨慎使用,优先原子操作)。 - 校验消息数据合法性:调用
stringtoProcess前,先检查buffer_up.mtext的格式和长度,过滤非法数据。
内容的提问来源于stack exchange,提问作者Youssef Tarek
相关产品推荐
相关产品推荐

