summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorH. Rittich <rittich@math.uni-wuppertal.de>2013-09-25 20:35:18 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-18 17:41:15 +0200
commitcf851c8577e796edac462fe3e060e80b11ec025f (patch)
tree808671c7656e4f2892799958c9fae129560fd63e /src/corelib/io
parent7126cdf48f5e28f1c2238c35960350921f849881 (diff)
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/corelib/io')
-rw-r--r--src/corelib/io/qprocess_unix.cpp41
1 files changed, 32 insertions, 9 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index d3cef1c155..6fa658ec94 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, &currentAction);
- if (currentAction.sa_handler == qt_sa_sigchld_handler) {
+ if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) {
::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
}
}