summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2020-09-10 13:30:59 -0700
committerThiago Macieira <thiago.macieira@intel.com>2020-09-17 00:43:47 +0000
commitd1fc991c6e3c45a5f93c925d49e3fe77ce6ce455 (patch)
tree53247bb739a409612cbfbf0f6c7497930031a312
parent2ed99ff5ca338ac02f71c347b1449d4662e6c221 (diff)
forkfd/Linux: ask clone() to use the SIGCHLD as the termination signal
Because of these lines in the Linux kernel (kernel/fork.c, see [1][3]): if (clone_flags & CLONE_VFORK) trace = PTRACE_EVENT_VFORK; else if (args->exit_signal != SIGCHLD) trace = PTRACE_EVENT_CLONE; else trace = PTRACE_EVENT_FORK; Without CLONE_VFORK (which we can't use), if the exit signal isn't SIGCHLD, the debugger will get a PTRACE_EVENT_CLONE, which makes it think the process we're starting is a thread, not a new process. Both gdb and lldb remain attached to the child and when it later performs an execve(), they get mightily confused. See gdb bug report[5]. The idea of not having an exit_signal was so that no SIGCHLD would be delivered to the parent process in the first place. That way, some misguided SIGCHLD handler (*cough* GLib *cough*) wouldn't reap our processes. Unfortunately, what I didn't realize was that the kernel sends SIGCHLD anyway (see [2][4]), so this defensive measure didn't actually work. Consequently, we can pass SIGCHLD to clone() and get the debuggers working again. [ChangeLog][Linux] Fixed an issue that would cause debugging a Qt application that uses QProcess to confuse both gdb and lldb if the Linux kernel was version 5.4 or higher. Behavior outside of a debugging session was not affected. [1] https://code.woboq.org/linux/linux/kernel/fork.c.html#_do_fork [2] https://code.woboq.org/linux/linux/kernel/signal.c.html#do_notify_parent [3] https://elixir.bootlin.com/linux/v5.8/source/kernel/fork.c#L2432 [4] https://elixir.bootlin.com/linux/v5.8/source/kernel/signal.c#L1925 [5] https://sourceware.org/bugzilla/show_bug.cgi?id=26562 Fixes: QTBUG-86319 Pick-to: 5.15 Change-Id: I2fc68c725ba649218bd9fffd1633863613537d42 Reviewed-by: Dimitrios Apostolou <jimis@qt.io> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Reviewed-by: hjk <hjk@qt.io>
-rw-r--r--src/3rdparty/forkfd/forkfd_linux.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/src/3rdparty/forkfd/forkfd_linux.c b/src/3rdparty/forkfd/forkfd_linux.c
index 923ced128d..c86e138b63 100644
--- a/src/3rdparty/forkfd/forkfd_linux.c
+++ b/src/3rdparty/forkfd/forkfd_linux.c
@@ -147,7 +147,7 @@ int system_forkfd(int flags, pid_t *ppid, int *system)
}
*system = 1;
- unsigned long cloneflags = CLONE_PIDFD;
+ unsigned long cloneflags = CLONE_PIDFD | SIGCHLD;
pid = sys_clone(cloneflags, &pidfd);
if (pid < 0)
return pid;
@@ -173,7 +173,7 @@ int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdoptions, struct
{
siginfo_t si;
int ret;
- int options = __WALL | convertForkfdWaitFlagsToWaitFlags(ffdoptions);
+ int options = convertForkfdWaitFlagsToWaitFlags(ffdoptions);
if ((options & WNOHANG) == 0) {
/* check if the file descriptor is non-blocking */