死锁(fork + malloc)libc(glibc-2.17,glibc-2.23)

时间:2017-10-23 16:09:18

标签: c deadlock libc

我遇到了一个非常讨厌的问题: 我有一个程序在开始时创建一个线程,这个线程将在执行期间启动其他东西(fork()immediatly后跟execve())。

这是我的程序到达(我认为)死锁的两个线程的bt:

线程2(LWP 8839):

#0 0x00007ffff6cdf736在__libc_fork()中.. / sysdeps / nptl / fork.c:125

_IO_new_proc_open中的

#1 0x00007ffff6c8f8c0(fp = fp @ entry = 0x7ffff00031d0,command = command @ entry = 0x7ffff6c26e20“ps -u brejon | grep \”cvc \“

#2 0x00007ffff6c8fbcc in _IO_new_popen(command = 0x7ffff6c26e20“ps -u user | grep \”cvc \“| wc -l”,mode = 0x42c7fd“r”)at iopopen.c:296

#3-4 ......

#5 0x00007ffff74d9434 in start_thread(arg = 0x7ffff6c27700)at pthread_create.c:333

克隆()中的

#6 0x00007ffff6d0fcfd在../sysdeps/unix/sysv/linux/x86_64/clim.S:109

线程1(LWP 8835):

#0 __lll_lock_wait_private()at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95

#1 0x00007ffff6ca0ad9 in malloc_atfork(sz = 140737337120848,caller =)at arena.c:179

文件门户网站__GI__IO_file_doallocate(fp = 0x17a72230)中的

#2 0x00007ffff6c8d875:127

#3 0x00007ffff6c9a964 in __GI__IO_doallocbuf(fp = fp @ entry = 0x17a72230)at genops.c:398

#4 0x00007ffff6c99de8 in _IO_new_file_overflow(f = 0x17a72230,ch = -1)at fileops.c:820

#5 0x00007ffff6c98f8a in _IO_new_file_xsputn(f = 0x17a72230,data = 0x17a16420,n = 682)at fileops.c:1331

#6 0x00007ffff6c6fcb2 in _IO_vfprintf_internal(s = 0x17a72230,format =,ap = ap @ entry = 0x7fffffffcf18)at vfprintf.c:1632

#7 0x00007ffff6c76a97 in __fprintf(stream =,format =)at fprintf.c:32

#8-11 ......

在主电源中的#12> 0x000000000042706e(argc = 3,argv = 0x7fffffffd698,envp = 0x7fffffffd6b8)电源/忽略/ .c:146

两者都坚持使用glibc-2.17和glibc-2.23

欢迎任何帮助:'D

编辑:

这是一个最小的例子:

  1 #include <stdlib.h>
  2 #include <pthread.h>
  3 #include <unistd.h>
  4 
  5 void * thread_handler(void * args)
  6 {
  7         char * argv[] = { "/usr/bin/ls" };
  8         char * newargv[] = { "/usr/bin/ls", NULL };
  9         char * newenviron[] = { NULL };
 10         while (1) {
 11                 if (vfork() == 0) {
 12                         execve(argv[0], newargv, newenviron);
 13                 }
 14         }
 15 
 16         return 0;
 17 }
 18 
 19 int main(void)
 20 {
 21         pthread_t thread;
 22         pthread_create(&thread, NULL, thread_handler, NULL);
 23 
 24         int * dummy_alloc;
 25 
 26         while (1) {
 27                 dummy_alloc = malloc(sizeof(int));
 28                 free(dummy_alloc);
 29         }
 30 
 31         return 0;
 32 }

环境: user:deadlock $ cat / etc / redhat-release

Scientific Linux版本7.3(氮气)

user:deadlock $ ldd --version

ldd(GNU libc)2.17

编辑2: rpm软件包版本为:glibc-2.17-196.el7.x86_64

我无法使用rpm包获取行号。这是BT使用glibc给出的分布:用debuginfo解决。

(gdb)线程应用所有bt

线程2(线程0x7ffff77fb700(LWP 59753)):

#0 vfork()at ../sysdeps/unix/sysv/linux/x86_64/vfork.S:44

在deadlock.c:11

中的thread_handler(args = 0x0)中的

#1 0x000000000040074e

#2 0x00007ffff7bc6e25 in start_thread(arg = 0x7ffff77fb700)at pthread_create.c:308

克隆()中的

#3 0x00007ffff78f434d在../sysdeps/unix/sysv/linux/x86_64/clim.S:113

线程1(线程0x7ffff7fba740(LWP 59746)):

#0 0x00007ffff7878226 in _int_free(av = 0x7ffff7bb8760,p = 0x602240,have_lock = 0)at malloc.c:3927

#1 0x00000000004007aa in main()at deadlock.c:28

1 个答案:

答案 0 :(得分:3)

这是一个自定义编译的glibc。安装可能出现问题。请注意Red Hat Enterprise Linux 7.4 backports a fix for a deadlock between malloc and fork,你错过了,因为你编译了自己的glibc。 fix for the upstream bug仅进入上游版本2.24,因此如果您将自定义构建基于此,则可能没有此修复程序。 (虽然回溯对于那个回溯看起来会有所不同。)

我认为我们修复了至少另一个2.17后与libio相关的死锁错误。

编辑我一直处理与fork相关的死锁已经太久了。发布的重现器存在多个问题:

  • 没有waitpid调用PID。因此,流程表将很快被僵尸填满。
  • 没有execve的错误检查。如果/usr/bin/ls路径名不存在(例如,在未经历UsrMove的系统上),则execve将返回,并且循环的下一次迭代将启动另一个 vfork致电。

我修复了两个问题(因为调试接近一个分叉炸弹的东西根本不好玩),但是我无法用glibc-2.17-196.el7.x86_64重现一个挂起。