diff options
author | H. Rittich <rittich@math.uni-wuppertal.de> | 2013-09-25 18:35:18 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-18 15:41:15 (GMT) |
commit | cf851c8577e796edac462fe3e060e80b11ec025f (patch) | |
tree | 808671c7656e4f2892799958c9fae129560fd63e /src | |
parent | 7126cdf48f5e28f1c2238c35960350921f849881 (diff) | |
download | Qt-cf851c8577e796edac462fe3e060e80b11ec025f.zip Qt-cf851c8577e796edac462fe3e060e80b11ec025f.tar.gz Qt-cf851c8577e796edac462fe3e060e80b11ec025f.tar.bz2 |
Fix sigchld-Handler
Changed the sigchld-Handler such that the SA_SIGINFO flag is handeled
correctly. Furthermore the signal mask is preserved such that the original
signal handler is not interrupted when not allowed.
Backport of the patch that was added to qtbase (Qt5) in
97279d05822a70da1fb3dab083d823a5f5a008fe
also contains the fix from
f83fa3c95e9ac6badc393c198c8bc08bc45bea96
.
Task-number: QTBUG-32979
Change-Id: Iec7663e7289ea5d95155f52cf8788ebf646cfabd
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index d3cef1c..6fa658e 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -128,17 +128,34 @@ static inline char *strdup(const char *data) 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; + + if (oldAction) + 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) @@ -199,10 +216,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); } @@ -225,7 +248,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); } } |