2

如果父进程在克隆子进程之后但在发送解除阻塞字节之前崩溃,则会发生这种情况SendContinueSignalToChild()。在这种情况下,管道文件句柄保持打开状态,并且子进程read(...)WaitForContinueSignal(). 崩溃后,孩子被 init 进程收养。

重现步骤

l. 模拟父级崩溃google_breakpad::ExceptionHandler::GenerateDump(CrashContext *context)

...
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL, NULL);

int r, status;
// Allow the child to ptrace us
sys_prctl(PR_SET_PTRACER, child, 0, 0, 0);


int *ptr = 0;  
*ptr = 42;     // <------- Crash here


SendContinueSignalToChild();
...
  1. 将处理后的信号之一发送给父级(例如 SIGSEGV),以便调用上述GenerateDump(...)方法。
  2. 观察到 parent 退出但 child 仍然存在,被阻止WaitForContinueSignal()

上述步骤的输出

dmytro@db:~$ ./test &
[1] 25050
dmytro@db:~$ Test: started

dmytro@db:~$ ps aflxw | grep test
0  1000 25050 18923  20   0  40712  2680 -      R    pts/37     0:13          |   |           \_ ./test
0  1000 25054 18923  20   0   6136   856 pipe_w S+   pts/37     0:00          |   |           \_ grep --color=auto test
dmytro@db:~$ kill -11 25050

[1]+  Segmentation fault      (core dumped) ./test
dmytro@db:~$ ps aflxw | grep test
0  1000 25058 18923  20   0   6136   852 pipe_w S+   pts/37     0:00          |   |           \_ grep --color=auto test
1  1000 25055  1687  20   0  40732   356 pipe_w S    pts/37     0:00          \_ ./test

1687 是初始化 pid。

在现实世界中,崩溃发生在与处理信号的线程平行的线程中。exit(0)注意:由于程序正常终止(即在并行线程中调用),也可能发生此问题。

在 Linux 3.3.8-2.2.、mips 和 i686 平台上测试。

所以,我的两个问题

  1. breakpad 库让孩子保持活力是预期的行为吗?我的期望是孩子应该在父母崩溃/退出后立即退出。
  2. 如果不是预期的行为,在父崩溃/退出后完成客户端的最佳解决方案是什么?

提前致谢!

4

1 回答 1

0

关于可能的解决方案的任何线索?

这也可能发生在关机崩溃期间,如果崩溃的线程不是主线程,并且父进程恰好在这个时间段从 main() 退出,所以显然它不是乍看起来不太可能发生。

目前,我认为这是由于 clone() 函数的 CLONE_FILES 标志而发生的。这导致如果父进程退出,子管道上的 read() 不会返回 EOF 的情况。

如果我们可以在 clone() 调用中安全地摆脱这个标志,我还没有完成检查。

于 2015-04-26T07:04:43.480 回答