如果父进程在克隆子进程之后但在发送解除阻塞字节之前崩溃,则会发生这种情况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();
...
- 将处理后的信号之一发送给父级(例如 SIGSEGV),以便调用上述
GenerateDump(...)
方法。 - 观察到 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 平台上测试。
所以,我的两个问题:
- breakpad 库让孩子保持活力是预期的行为吗?我的期望是孩子应该在父母崩溃/退出后立即退出。
- 如果不是预期的行为,在父崩溃/退出后完成客户端的最佳解决方案是什么?
提前致谢!