对结构体中的变量进行原子操作时程序异常coredump

现象描述

程序调用原子操作函数对结构体中的变量进行原子操作,程序coredump,堆栈如下:

Program received signal SIGBUS, Bus error. 
0x000000000040083c in main () at /root/test/src/main.c:19 
19          __sync_add_and_fetch(&a.count, step); 
(gdb) disassemble 
Dump of assembler code for function main: 
   0x0000000000400824 <+0>:     sub     sp, sp, #0x10 
   0x0000000000400828 <+4>:     mov     x0, #0x1                        // #1 
   0x000000000040082c <+8>:     str     x0, [sp, #8] 
   0x0000000000400830 <+12>:    adrp    x0, 0x420000 <__libc_start_main@got.plt> 
0x0000000000400834 <+16>:    add     x0, x0, #0x31 // 将变量的地址放入到x0寄存器
   0x0000000000400838 <+20>:    ldr     x1, [sp, #8] // 指定ldxr取数据的长度(此处为8字节)
=> 0x000000000040083c <+24>:    ldxr    x2, [x0] // ldxr从x0寄存器指向的内存地址中取值
   0x0000000000400840 <+28>:    add     x2, x2, x1 
   0x0000000000400844 <+32>:    stlxr   w3, x2, [x0] 
   0x0000000000400848 <+36>:    cbnz    w3, 0x40083c <main+24> 
   0x000000000040084c <+40>:    dmb     ish 
   0x0000000000400850 <+44>:    mov     w0, #0x0                        // #0 
   0x0000000000400854 <+48>:    add     sp, sp, #0x10 
   0x0000000000400858 <+52>:    ret 
End of assembler dump. 
(gdb) p /x $x0 
$4 = 0x420039 // x0寄存器存放的变量地址不在8字节地址对齐处

问题原因

ARM64平台对变量的原子操作、锁操作等用到了ldaxr、stlxr等指令,这些指令要求变量地址必须按变量长度对齐,否则执行指令会触发异常,导致程序coredump。

一般是因为代码中对结构体进行强制字节对齐,导致变量地址不在对齐位置上,对这些变量进行原子操作、锁操作等会触发问题。

处理步骤

  1. 在代码中搜索“#pragma pack”关键字(该宏改变了编译器默认的对齐方式)。
  2. 找到使用了字节对齐的结构体,修改代码。

    如果结构体中变量会被作为原子操作、自旋锁、互斥锁、信号量、读写锁的输入参数,则需要修改代码保证这些变量按变量长度对齐