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

Glibc-2.24中pthread_mutex_lock传入0x2无效地址的排查与调试咨询

POSIX线程崩溃问题排查(mutex参数异常为0x2)

问题背景

当前排查一个信号处理线程崩溃问题,崩溃发生在POSIX pthread API __GI___pthread_mutex_lock(mutex=0x2),mutex参数被意外设置为无效地址0x2。以下是core文件的GDB回溯信息:

Thread 2 (LWP 26849):
#0  __nptl_deallocate_tsd () at pthread_create.c:200
#1  0xf72af5da in start_thread (arg=0x0) at pthread_create.c:346
#2  0xf698d5f2 in ?? () at ../sysdeps/unix/sysv/linux/arm/clone.S:86
   from /tools/toolchain/arm/armbe-none-linux-gnueabi_2017/usr/armeb-buildroot-linux-gnueabi/sysroot/lib32/libc.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Thread 1 (LWP 26850):
#0  __libc_do_syscall () at ../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47
#1  0xf691d2d2 in __libc_signal_restore_set (set=0xf65fe560) at ../sysdeps/unix/sysv/linux/nptl-signals.h:79
#2  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:55
#3  0xf691dfba in __GI_abort () at abort.c:89
#4  0xf691861a in __assert_fail_base (fmt=0xf69c5f80 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0xf72b8b1c "mutex->__data.__owner == 0",
    assertion@entry=0x2 <error: Cannot access memory at address 0x2>, file=file@entry=0xf65fef50 "", line=1, line@entry=4137570440,
    function=function@entry=0xf72b8b90 <__PRETTY_FUNCTION__.10382> "__pthread_mutex_lock") at assert.c:92
#5  0xf69186ae in __GI___assert_fail (assertion=0x2 <error: Cannot access memory at address 0x2>, file=0xf65fef50 "", line=4137570440, line@entry=81,
    function=0xf72b8b90 <__PRETTY_FUNCTION__.10382> "__pthread_mutex_lock") at assert.c:101
#6  0xf72b15d6 in __GI___pthread_mutex_lock (mutex=0x2) at pthread_mutex_lock.c:81
#7  0xf6a29820 in handle_process_exit () at signal_handler.c:258
#8  0xf6a29ba0 in signal_handler (param=0) at signal_handler.c:331
#9  0xf6a25e98 in task_init (param=0x2efe24) at task/tasks.c:403
#10 0xf72af5ce in start_thread (arg=0x1) at pthread_create.c:335
#11 0xf698d5f2 in ?? () at ../sysdeps/unix/sysv/linux/arm/clone.S:86
   from /tools/toolchain/arm/armbe-none-linux-gnueabi_2017/usr/armeb-buildroot-linux-gnueabi/sysroot/lib32/libc.so.6
---Type <return> to continue, or q <return> to quit---
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) f 7
#7  0xf6a29820 in handle_process_exit () at sig/silpi_signal_handler.c:258
258     sig/signal_handler.c: No such file or directory.
(gdb) p @tmr_exit_mutex
Unknown address space specifier: "tmr_exit_mutex"
(gdb) p &tmr_exit_mutex
$1 = (pthread_mutex_t *) 0xf6a43fb8 <tmr_exit_mutex>
(gdb) f 6
#6  0xf72b15d6 in __GI___pthread_mutex_lock (mutex=0x2) at pthread_mutex_lock.c:81
81      pthread_mutex_lock.c: No such file or directory.
(gdb) p mutex
$2 = (pthread_mutex_t *) 0x2
(gdb) p &tmr_exit_mutex
$3 = (pthread_mutex_t *) 0xf6a43fb8 <tmr_exit_mutex>
(gdb) ptype tmr_exit_mutex
type = union {
    struct __pthread_mutex_s __data;
    char __size[24];
    long __align;
}
(gdb) p tmr_exit_mutex
$4 = {__data = {__lock = 0, __count = 0, __owner = 0, __kind = 0, __nusers = 0, {__spins = 0, __list = {__next = 0x0}}},
  __size = '\000' <repeats 23 times>, __align = 0}
(gdb)

注:handle_process_exit()中调用pthread_mutex_lock(&tmr_exit_mutex),tmr_exit_mutex地址0xf6a43fb8正常,但传入__GI___pthread_mutex_lock后变为0x2。查看Glibc-2.24的pthread_mutex_lock.c源码,地址损坏发生在第81行,第65行的assert (sizeof(mutex->__size) >= sizeof(mutex->__data));未触发。


1. 可能的原因

  • 栈帧损坏:回溯中两个线程均提示corrupt stack?,说明调用栈已被破坏。handle_process_exit调用pthread_mutex_lock时,栈上的参数(&tmr_exit_mutex)被覆盖为0x2,大概率是信号处理函数中存在栈溢出、内存越界写操作,覆盖了函数调用的参数存储区域。
  • 寄存器值被篡改:ARM架构下函数参数通常通过寄存器(如r0)传递,如果handle_process_exit调用pthread_mutex_lock前,寄存器r0被意外修改(比如其他线程非法内存访问、硬件异常、代码错误操作),会导致传入的mutex地址变为0x2。
  • 信号异步干扰:崩溃发生在信号处理线程,若信号处理过程中触发其他异步信号,或在信号处理函数中调用了非异步安全的操作,可能破坏栈或寄存器状态,导致参数传递异常。
  • 线程局部存储(TLS)损坏:Thread2的回溯涉及__nptl_deallocate_tsd(线程局部存储释放),TLS区域损坏可能间接影响主线程的栈或参数传递逻辑。
  • 内存越界写全局区域:虽然tmr_exit_mutex地址正常,但如果有代码越界写入破坏了handle_process_exit中引用该变量的地址计算逻辑,也可能导致参数异常,但这种概率较低。

2. GDB及开源工具调试方法

  • GDB栈帧与寄存器分析:
    • 进入handle_process_exit栈帧(frame 7),用x/16x $sp查看栈内存,定位原本存放&tmr_exit_mutex的位置,检查是否被修改为0x2,同时观察相邻内存的异常值,判断越界写的来源。
    • 执行info registers查看ARM寄存器状态,重点确认调用pthread_mutex_lock前r0寄存器的值是否等于&tmr_exit_mutex,定位参数何时被篡改。
    • 启用set backtrace past-main和set backtrace past-entry,尝试获取更完整的栈回溯,确认栈损坏的起始点。
  • 内存错误检测工具:
    • 使用valgrind --tool=memcheck运行程序,检测内存越界、栈溢出等问题,重点关注信号处理函数中的内存操作。
    • 用AddressSanitizer编译程序(添加-fsanitize=address参数),精准定位内存越界写的位置,适合支持该工具的目标平台。
  • 断点与观察点设置:
    • 在handle_process_exit调用pthread_mutex_lock的位置设置断点,执行到断点时检查参数是否正确,再单步进入pthread_mutex_lock,观察参数何时变为0x2。
    • 对栈上参数的存储地址设置写观察点(如watch *$sp+4,根据ARM栈传递规则调整偏移),触发时查看调用栈,找到修改该地址的代码。
  • 反汇编分析:
    • 对handle_process_exit和pthread_mutex_lock执行disassemble命令,查看参数传递的汇编逻辑(寄存器/栈传递),分析参数被篡改的具体环节。

3. 无法复现时需收集的日志/信息

  • 完整Core文件:确保系统开启core dump(执行ulimit -c unlimited),收集崩溃时的core文件,包含进程内存、寄存器、栈帧的完整状态。
  • 系统日志:收集/var/log/messages、dmesg输出,排查是否有硬件错误(如内存ECC异常、总线故障)、OOM Killer记录或其他进程的异常干扰。
  • 进程业务日志:
    • 添加日志记录handle_process_exit调用pthread_mutex_lock前&tmr_exit_mutex的地址,以及函数的进入/退出日志,确认参数传递前的状态。
    • 记录崩溃前的信号处理情况,比如收到的信号类型、处理次数、相关业务操作。
  • 线程状态快照:定期用pstack/gstack工具收集线程栈信息,或在信号处理函数中添加线程栈打印逻辑,保存崩溃前的线程运行状态。
  • 环境与编译信息:记录编译器版本、Glibc版本(此处为2.24)、目标平台架构(ARM)、工具链版本,排查是否存在已知的库或编译器bug。
  • 内存映射信息:收集崩溃进程的/proc/[pid]/maps文件,查看内存布局,确认0x2地址所在区域及tmr_exit_mutex所在内存段的权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 05:35:56