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

sbdsn5lh  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(126)

我目前正在处理一个问题,其中一个线程负责处理不同类型的信号。有趣的是,崩溃发生在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或任何外部开源工具调试这些问题?
此外,导致未定义行为的竞争条件已经发生,因为互斥体必须由于其他线程而被销毁,但很难重现相同的场景,因此,您能否为我提供一些见解,让我了解每当此问题再次发生时,我应该收集哪些不同类型的日志,因为我正在创建调试映像,以便在此问题再次发生时捕获我可以收集的所有信息再次相遇?
总之,我想知道/调试传递给pthread_mutex_lock(mutex=0x2) glibc-2.24 pthread API的mutex参数的地址的原因是什么?

e5njpo68

e5njpo681#

正如AndrewHenle正确指出的那样,从信号处理程序使用pthread_*函数是未定义的行为--您必须使用可编程信号安全的构造,例如原子变量。
我观察到损坏发生在第81行,只是因为如果损坏发生在更早的时候,那么第65行的assert (sizeof(mutex->__size) >= sizeof(mutex->__data));就会失败,
你错了:assert可以很好地工作,* 不管 * mutex的值是多少--它根本不计算mutex,它只Assert所涉及的不同类型的 * 大小 * 之间的关系。
在handle_process_exit()函数中,我们调用pthread_mutex_lock(mutex = &tmr_exit_mutex)
我们不知道mutex在这种情况下是什么,如果它是一个局部变量(没有取地址),那应该没问题,但如果它是一个全局变量,那么你可能有一个数据竞争。
没有http://stackoverflow.com/help/mcve,任何人都不可能进一步帮助您。
但是使用消毒剂在这里 * 不太可能 * 有帮助,因为libpthreadlibc本身没有 Jmeter 化。

相关问题