为什么 Linux C 语言程序中的信号量会导致 SIGABRT 中止?

Why does a semaphore in a Linux C language program cause SIGABRT Aborted?

提问人:czg 提问时间:9/16/2022 最后编辑:NathanOliverczg 更新时间:9/16/2022 访问量:63

问:

我的开发环境是 CentOS 7.9-x86_64,编译器使用的是 gcc11。

[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]# 
[root@dev src]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
[root@dev src]# 
[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]#

下面是我的代码片段:

  1. 这是一个定义结构 EuclidCommand 的头文件,此结构包含一个信号量。
#include <semaphore.h>

typedef struct euclid_command
{
    char *bytes;
    char *result;
    sem_t sem;
} EuclidCommand;
  1. 以下是程序逻辑部分。
/**
* Allocate a piece of memory for the structure object EuclidCommand, and allocate 
* an additional 4 bytes as additional information for this structure object.
*/
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);

/**
* Submit the task object to another thread for processing, that thread will increment 
* the value of the semaphore by 1 after execution is complete.
*/
submit_command(task);

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

// do something

上面的代码可以正确执行。 接下来,我做了一个小改动,将额外内存的字节数从 4 改为 2。

/**
* Allocate a piece of memory for the structure object EuclidCommand, and allocate 
* an additional 2 bytes as additional information for this structure object.
*/
int hidden = 2;
void *obj_head = malloc(hidden + sizeof(EuclidCommand));
memset(obj_head, 0, hidden + sizeof(EuclidCommand));
EuclidCommand *task = obj_head + hidden;

重新编译代码后再次执行程序。当执行“sem_wait(&(task->sem));”代码行时,程序将失败。使用 gdb 查看当时的程序栈,如下图所示:enter image description here

我想这个问题的原因与字节对齐有关,但我不确定这个问题的真正原因。希望能遇到熟悉Linux C语言开发的朋友帮我解答。
谢谢

C Linux的

评论

4赞 Some programmer dude 9/16/2022
请不要发布文字图片
6赞 Thomas Jager 9/16/2022
你想用什么来完成?您正在按字节偏移 a 的开头。这可能会完全破坏成员的对齐方式。此外,算术 with 是编译器扩展,不是标准的。EuclidCommand *task = obj_head + hidden;EuclidCommandhiddenvoid *
4赞 Gerhardh 9/16/2022
如果要在分配中添加一些额外的字节,可以在正在使用的结构结束后添加它们。为此,可以使用灵活的数组成员。但是,仅仅在指针周围移动而不注意对齐方式是不会飞起来的。
4赞 Tom Karzes 9/16/2022
C 语言中的每种数据类型都有一些最低要求的对齐方式。 保证它返回的指针将充分对齐,以满足任何此类对齐要求。正如您所看到的,将 2(或 4)添加到此类指针违反了该保证。malloc
0赞 czg 9/19/2022
谢谢大家,我已经解决了这个问题,确实是字节对齐断了导致的,但是我不得不在分配的内存上隐藏一些元信息,所以我将隐藏的字节数调整为8,这样保证了字节始终对齐。

答: 暂无答案