diff options
author | Simeon Bird <bladud@gmail.com> | 2013-02-14 00:56:02 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-02-28 01:27:30 (GMT) |
commit | f391ec72c2e4416bf8e5d7482ace49247cc2017c (patch) | |
tree | d491fc95285be5defb03e0e1c8ac3caec246314c /src/corelib | |
parent | 848a584dc0ab22cceb64d891b42525ff789ac0db (diff) | |
download | Qt-f391ec72c2e4416bf8e5d7482ace49247cc2017c.zip Qt-f391ec72c2e4416bf8e5d7482ace49247cc2017c.tar.gz Qt-f391ec72c2e4416bf8e5d7482ace49247cc2017c.tar.bz2 |
Fix QTBUG-18934 by checking return value of qt_safe_pipe
When QProcess->start() is called, Qt creates a pipe to the process to
get its exit value and output.
It does this with qt_create_pipe, which calls qt_safe_pipe.
qt_safe_pipe, on failure, returns 1. qt_create_pipe then
sets errno and returns void.
The calling function, QProcessPrivate::startProcess, does not check
errno, and thus continues to fork the process, assuming the pipe has been
created successfully.
The child process then has no way to pass its exit value to the calling
process, since the communication pipes it would normally use do not
exist, and thus when it exits it becomes a zombie.
As a bonus, if waitForFinished is called on a broken process, a crash
results because it is trying to wait on a pipe which does not exist.
The fix makes qt_create_pipe return an integer, and QProcess::startProcess
check the return value, set processError and not create the child
process.
Task-Number: QTBUG-18934
Cherry-picked from qtbase f575dc214630b3e3ebd66477a623c78405724468
Change-Id: I2e1effdd0617be5b8c5492bcbcf5f2b1584b2241
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 8514d4e..c422a89 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -326,16 +326,18 @@ void QProcessManager::unlock() mutex.unlock(); } -static void qt_create_pipe(int *pipe) +static int qt_create_pipe(int *pipe) { if (pipe[0] != -1) qt_safe_close(pipe[0]); if (pipe[1] != -1) qt_safe_close(pipe[1]); - if (qt_safe_pipe(pipe) != 0) { + int pipe_ret = qt_safe_pipe(pipe); + if (pipe_ret != 0) { qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", pipe, qPrintable(qt_error_string(errno))); } + return pipe_ret; } void QProcessPrivate::destroyPipe(int *pipe) @@ -367,7 +369,8 @@ bool QProcessPrivate::createChannel(Channel &channel) if (channel.type == Channel::Normal) { // we're piping this channel to our own process - qt_create_pipe(channel.pipe); + if (qt_create_pipe(channel.pipe) != 0) + return false; // create the socket notifiers if (threadData->eventDispatcher) { @@ -451,7 +454,8 @@ bool QProcessPrivate::createChannel(Channel &channel) Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE); Q_PIPE pipe[2] = { -1, -1 }; - qt_create_pipe(pipe); + if (qt_create_pipe(pipe) != 0) + return false; sink->pipe[0] = pipe[0]; source->pipe[1] = pipe[1]; @@ -545,10 +549,15 @@ void QProcessPrivate::startProcess() // Initialize pipes if (!createChannel(stdinChannel) || !createChannel(stdoutChannel) || - !createChannel(stderrChannel)) + !createChannel(stderrChannel) || + qt_create_pipe(childStartedPipe) != 0 || + qt_create_pipe(deathPipe) != 0) { + processError = QProcess::FailedToStart; + q->setErrorString(qt_error_string(errno)); + emit q->error(processError); + cleanup(); return; - qt_create_pipe(childStartedPipe); - qt_create_pipe(deathPipe); + } if (threadData->eventDispatcher) { startupSocketNotifier = new QSocketNotifier(childStartedPipe[0], @@ -1336,10 +1345,15 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a // To catch the startup of the child int startedPipe[2]; - qt_safe_pipe(startedPipe); + if (qt_safe_pipe(startedPipe) != 0) + return false; // To communicate the pid of the child int pidPipe[2]; - qt_safe_pipe(pidPipe); + if (qt_safe_pipe(pidPipe) != 0) { + qt_safe_close(startedPipe[0]); + qt_safe_close(startedPipe[1]); + return false; + } pid_t childPid = fork(); if (childPid == 0) { |