首页 > 解决方案 > linux c程序中发生Coredump(Redhat 8.3.1)

问题描述

在我的程序中,_Decimal128在 linux 上的嵌套结构上使用时会发生 coredump。
它在满足以下所有条件时发生。

首先,#pragma pack(8)声明。
第二,第三嵌套结构
第三,_Decimal128键入地址作为函数的参数。

我正在寻找核心转储的原因。
开发环境为Redhat 8.3.1,编译成gcc。
示例代码如下。

#include <stdio.h>
#pragma pack(8)   // without this line, it is success

struct _c {
    int c1;
   _Decimal128 c2;
};
struct _b {
   int b1;
   _Decimal128 b2; 
   struct _c b3;      //3rd nested structure
};
struct _a {
   int a1;
   _Decimal128 a2;
   struct _b a3;     // 2nd nested structure
};

void func1(struct _c *cptr)
{
   if (cptr->c2 == 0)     // if argument type is structure, it is success
      printf("[func1]\n");
}

void func2(_Decimal128 *ptr)
{
   if (*ptr == 0)        // if argument type is _Decimal128, it occurs coredump
      printf("[func2]\n");
}

int main()
{
   struct _a a;
   struct _b b;
   _Decimal128 t = 0;
   b.b2 = t;
   b.b3.c2 = t;
   a.a3 = b;

   func1(&a.a3.b3);  // if argument is 3rd structure address, it is success
   func2(&a.a3.b2);  // if argument is _Decimal128 address of 2rd structure, it is sunccess
   func2(&a.a3.b3.c2);  // if argument is _Decimal128 address of 3rd structure, it occurs coredump
}      

结果是,

[func1]
[func2]
Memory fault(coredump)

如果我从上面的源代码中删除#pragma pack(8)行,结果如下。

[func1]
[func2]
[func2]

标签: clinuxdecimalredhatcoredump

解决方案


#pragma pack(8)将告诉编译器结构的成员应该对齐到 8 个字节,忽略每种类型的对齐要求。

_Decimal128可能是 16 字节类型,其对齐要求可能是 16 字节。

使用指向结构的指针struct _c *cptr,编译器可以知道成员使用了非通常的对齐方式,并且可能需要一些特殊的方式来处理_Decimal128成员。

另一方面,_Decimal128直接使用指向的指针,编译器将假定指针是指向_Decimal128成员的有效(通常对齐)指针。因此,当传递的不是正常的指向_Decimal128.

让我们用一些例子来验证这个陈述。

首先,让我们检查对齐要求和_Decimal128成员的地址:

#include <stdio.h>
#pragma pack(8)   // without this line, it is success

struct _c {
    int c1;
   _Decimal128 c2;
};
struct _b {
   int b1;
   _Decimal128 b2; 
   struct _c b3;      //3rd nested structure
};
struct _a {
   int a1;
   _Decimal128 a2;
   struct _b a3;     // 2nd nested structure
};

int main(void) {
    struct _a a;
    printf("sizeof(_Decimal128) = %d\n", (int)sizeof(_Decimal128));
    printf("_Alignof(_Decimal128) = %d\n", (int)_Alignof(_Decimal128));
    printf("&a = %p\n", (void*)&a);
    printf("&a.a3.b3.c2 = %p\n", (void*)&a.a3.b3.c2);
    return 0;
}

输出示例

sizeof(_Decimal128) = 16
_Alignof(_Decimal128) = 16
&a = 0x7fffee270d70
&a.a3.b3.c2 = 0x7fffee270da8

在这种环境中, 的对齐要求_Decimal128是 16 字节,但该成员_Decimal128 c的地址不能被 16 整除。

其次,这是@AKX 的示例,它显示了函数(使用指向结构的指针)和函数(使用指向 的指针)Decimal128可能会以不同的方式处理:func1func2_Decimal128

func1:
        subq    $8, %rsp
        movdqa  .LC1(%rip), %xmm1
        movdqu  8(%rdi), %xmm0
func2:
        subq    $8, %rsp
        movdqa  .LC1(%rip), %xmm1
        movdqa  (%rdi), %xmm0

在此示例中,movdqu指令用于加载_Decimal128函数中的值func1movdqu可以使用未对齐的内存。

另一方面,movdqa指令用于_Decimal128函数中的值func2movdqa在尝试使用未对齐的内存时生成一般保护异常。

这表明func1可以使用未对齐的内存,而func2在此示例中不能。


推荐阅读