summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qprocess_unix.cpp
diff options
context:
space:
mode:
authorSergio Ahumada <sergio.ahumada@digia.com>2013-09-21 17:32:39 +0200
committerSergio Ahumada <sergio.ahumada@digia.com>2013-09-21 17:33:15 +0200
commita5d34b34fbd867bd13ce94cdaf55d96576d4d14d (patch)
treebb3b8b902f13bda65e49485a789f0eca07329ab5 /src/corelib/io/qprocess_unix.cpp
parent5957f245c6c77c98d7e90d614c9fe2cdbfe7e8e6 (diff)
parenta23ff58d716f62b02ec825a3ea3c6b07616ee3f0 (diff)
Merge branch 'stable' into dev
Diffstat (limited to 'src/corelib/io/qprocess_unix.cpp')
-rw-r--r--src/corelib/io/qprocess_unix.cpp40
1 files changed, 31 insertions, 9 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 9868ea624a..eab3890beb 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, &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);
}