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

Linux C程序中信号量触发SIGABRT终止的原因排查

字节对齐导致信号量操作失败问题排查

开发环境

[root@dev src]# uname -a
Linux dev 3.10.0-1160.24.1.el7.x86_64 #1 SMP Thu Apr 8 19:51:47 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[root@dev src]# 
[root@dev src]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
[root@dev src]# 
[root@dev src]# gcc --version
gcc (GCC) 11.2.1 20220127 (Red Hat 11.2.1-9)
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[root@dev src]#

问题场景

定义包含信号量的结构体:

#include <semaphore.h>

typedef struct euclid_command
{
    char *bytes;
    char *result;
    sem_t sem;
} EuclidCommand;

原本代码中为结构体分配内存时额外预留4字节,程序可正常执行:

/**
* 为EuclidCommand结构体对象分配内存,额外预留4字节作为附加信息
*/
int hidden = 4;
void *obj_head = malloc(hidden + sizeof(EuclidCommand));
memset(obj_head, 0, hidden + sizeof(EuclidCommand));
EuclidCommand *task = obj_head + hidden;
task->bytes = buf;

sem_init(&(task->sem), 0, 0);

/**
* 将任务对象提交至其他线程处理,线程执行完成后会将信号量值加1
*/
submit_command(task);

sem_wait(&(task->sem));
sem_destroy(&(task->sem));

// do something

当把预留字节数改为2后,程序在执行sem_wait(&(task->sem));时触发失败,gdb查看的程序栈显示信号量操作相关函数异常。

问题原因

确实是字节对齐导致的问题:

  • 在x86_64架构的CentOS 7系统中,sem_t类型的对象要求4字节对齐(其内部成员依赖该对齐规则)。
  • 当预留2字节时,obj_head + 2的地址无法满足EuclidCommand结构体的对齐要求,结构体中sem_t成员的地址会落在非对齐位置。
  • 信号量相关函数(sem_init、sem_wait)依赖sem_t对象处于正确对齐的内存地址,非对齐访问会破坏信号量内部数据结构,直接导致操作失败。
  • 之前预留4字节时,obj_head + 4刚好是4字节对齐地址,符合结构体的对齐要求,因此程序正常运行。

解决方案

  1. 保证结构体地址对齐:计算结构体的对齐要求,调整预留空间或偏移量,确保task指针指向的地址满足对齐规则:
#include <stdalign.h>

// 获取EuclidCommand的对齐要求
size_t align = alignof(EuclidCommand);
int hidden = 2;
// 计算需要补充的偏移量,使最终地址对齐
size_t offset = (align - (hidden % align)) % align;
void *obj_head = malloc(hidden + offset + sizeof(EuclidCommand));
memset(obj_head, 0, hidden + offset + sizeof(EuclidCommand));
EuclidCommand *task = (void*)((char*)obj_head + hidden + offset);
  1. 调整内存布局:将附加信息存储在结构体末尾,或使用独立内存块存储,避免破坏结构体的对齐。
  2. 使用对齐分配函数:通过posix_memalign分配对齐的内存块,再在头部预留附加信息空间,从对齐地址开始初始化结构体。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 12:20:28