diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index e9957d2384..7e42f4b722 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -121,17 +121,33 @@ static const int errorBufferMax = 512; static int qt_qprocess_deadChild_pipe[2]; static struct sigaction qt_sa_old_sigchld_handler; -static void qt_sa_sigchld_handler(int signum) +static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context) { + // *Never* use the info or contect variables in this function + // (except for passing them to the next signal in the chain). + // We cannot be sure if another library or if the application + // installed a signal handler for SIGCHLD without SA_SIGINFO + // and fails to pass the arguments to us. If they do that, + // these arguments contain garbage and we'd most likely crash. + qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1); #if defined (QPROCESS_DEBUG) fprintf(stderr, "*** SIGCHLD\n"); #endif - // load it as volatile - void (*oldAction)(int) = ((volatile struct sigaction *)&qt_sa_old_sigchld_handler)->sa_handler; - if (oldAction && oldAction != SIG_IGN) - oldAction(signum); + // load as volatile + volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler; + + if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) { + void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction; + + oldAction(signum, info, context); + } else { + void (*oldAction)(int) = vsa->sa_handler; + + if (oldAction && oldAction != SIG_IGN) + oldAction(signum); + } } static inline void add_fd(int &nfds, int fd, fd_set *fdset) @@ -197,10 +213,16 @@ QProcessManager::QProcessManager() // set up the SIGCHLD handler, which writes a single byte to the dead // child pipe every time a child dies. + struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = qt_sa_sigchld_handler; - action.sa_flags = SA_NOCLDSTOP; + // use the old handler as template, i.e., preserve the signal mask + // otherwise the original signal handler might be interrupted although it + // was marked to never be interrupted + ::sigaction(SIGCHLD, NULL, &action); + action.sa_sigaction = qt_sa_sigchld_sigaction; + // set the SA_SIGINFO flag such that we can use the three argument handler + // function + action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler); processManagerInstance = this; @@ -225,7 +247,7 @@ QProcessManager::~QProcessManager() struct sigaction currentAction; ::sigaction(SIGCHLD, 0, ¤tAction); - if (currentAction.sa_handler == qt_sa_sigchld_handler) { + if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) { ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0); }