为什么垃圾地址值 (0x2) 存储在 Glibc-2.24 POSIX pthread API 中的互斥指针中:__GI___pthread_mutex_lock(mutex=0x2)

问题描述 投票:0回答:1

我目前正在解决一个问题,即负责处理不同类型信号的一个线程发生崩溃。有趣的是,崩溃发生在 POSIX pthread API 中:

__GI___pthread_mutex_lock(mutex=0x2)
,由于某些未知原因,值
0x2
虚假地址在
pthread_mutex_lock()
API 范围内的互斥变量中更新。请参考以下从核心文件收集的 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(mutex = &tmr_exit_mutex)
pthread POSIX API,您可以观察到
tmr_exit_mutex (0xf6a43fb8)
变量的地址在第 6 帧和第 7 帧中是相同的(意味着它没有损坏),但由于某些未知原因,传递给互斥体参数的地址被损坏,并且虚假地址
0x02
作为参数传递给此
__GI___pthread_mutex_lock(mutex=0x2)
pthread POSIX API。

当我查看 glibc-2.24 源代码树中的

pthread_mutex_lock.c
文件的源代码时,可在以下位置获取:https://elixir.bootlin.com/glibc/glibc-2.24/source/nptl/pthread_mutex_lock.c 。我观察到腐败发生在第 81 行,只是因为如果腐败发生得更早,那么第 65 行的
assert (sizeof(mutex->__size) >= sizeof(mutex->__data));
就会失败,所以我无法对可能发生的情况做出任何解释。

任何人都可以向我提供有关为什么会发生这种情况以及如何使用 GDB 或任何外部开源工具(如果可能)调试这些问题的详细信息吗?

此外,导致未定义行为的竞争条件已经发生,因为互斥锁肯定已由于其他线程而被破坏,但很难重现相同的场景,所以您能否向我提供有关不同类型日志的见解每当此问题再次发生时我都应该收集,因为我正在创建调试映像以捕获每当此问题再次遇到时我可以收集的所有信息?

总而言之, 我想知道/调试地址被传递给

mutex
glibc-2.24 pthread API 的
pthread_mutex_lock(mutex=0x2)
参数的原因是什么?

c debugging gdb race-condition glibc
1个回答
1
投票

正如 Andrew Henle 正确指出的那样,在信号处理程序中使用

pthread_*
函数是未定义的行为——您必须使用异步信号安全结构,例如原子变量。

我观察到损坏发生在第 81 行,只是因为如果损坏发生得更早,那么第 65 行的

assert (sizeof(mutex->__size) >= sizeof(mutex->__data));
就会失败,

你错了:无论

assert
的值如何,mutex都可以正常工作——它根本不评估
mutex
,它只断言不同类型的
sizes
之间的关系参与其中。

在handle_process_exit()函数中我们调用
pthread_mutex_lock(mutex = &tmr_exit_mutex)


我们不知道在这种情况下
mutex

是什么。如果它是一个局部变量(没有获取其地址),那应该没问题,但如果它是一个全局变量,那么你可能会遇到数据竞争。

如果没有 

http://stackoverflow.com/help/mcve

,任何人都不太可能能够为您提供进一步的帮助。 但是使用消毒剂

不太可能

有帮助,因为libpthread

libc
本身没有检测到。
    

© www.soinside.com 2019 - 2024. All rights reserved.