From 6d78b7a0c46ea04f4bb771d960e2f7dff1362341 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 16 Jul 2015 17:46:42 -0700 Subject: [PATCH] QProcess: report the syscall that failed in the Unix child process Prefix the error string message with either "chdir" or the "execvXX"- family function that failed. In order to simplify the process, I also made it transmit local 8-bit data instead of UTF-16 (this also avoids memory allocation with QString). Since there are now two write(2) calls, it's possible for the parent process to be woken up and read(2) only the first. The parent process now needs to wait for EOF. Change-Id: Ib306f8f647014b399b87ffff13f1956199a5aee0 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/io/qprocess.cpp | 2 +- src/corelib/io/qprocess_unix.cpp | 25 ++++++++++++++----- .../auto/corelib/io/qprocess/tst_qprocess.cpp | 7 ++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index cdae149678a..09a471e7db6 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1194,7 +1194,7 @@ bool QProcessPrivate::_q_startupNotification() } q->setProcessState(QProcess::NotRunning); - setErrorAndEmit(QProcess::FailedToStart); + setErrorAndEmit(QProcess::FailedToStart, errorString); // the error string was already set #ifdef Q_OS_UNIX // make sure the process manager removes this entry waitForDeadChild(); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 63480dfc6b6..a958aa43220 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -672,6 +672,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv qt_safe_close(childStartedPipe[0]); // enter the working directory + const char *callthatfailed = "chdir: "; if (workingDir && QT_CHDIR(workingDir) == -1) { // failed, stop the process goto report_errno; @@ -683,6 +684,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv // execute the process if (!envp) { qt_safe_execvp(argv[0], argv); + callthatfailed = "execvp: "; } else { if (path) { char **arg = path; @@ -700,15 +702,19 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv #endif qt_safe_execve(argv[0], argv, envp); } + callthatfailed = "execve: "; } // notify failure + // we're running in the child process, so we don't need to be thread-safe; + // we can use strerror report_errno: - QString error = qt_error_string(errno); + const char *msg = strerror(errno); #if defined (QPROCESS_DEBUG) - fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n", qPrintable(error)); + fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n", msg); #endif - qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar)); + qt_safe_write(childStartedPipe[1], callthatfailed, strlen(callthatfailed)); + qt_safe_write(childStartedPipe[1], msg, strlen(msg)); qt_safe_close(childStartedPipe[1]); childStartedPipe[1] = -1; } @@ -716,8 +722,15 @@ report_errno: bool QProcessPrivate::processStarted() { - ushort buf[errorBufferMax]; - int i = qt_safe_read(childStartedPipe[0], &buf, sizeof buf); + char buf[errorBufferMax]; + int i = 0; + int ret; + do { + ret = qt_safe_read(childStartedPipe[0], buf + i, sizeof buf - i); + if (ret > 0) + i += ret; + } while (ret > 0 && i < int(sizeof buf)); + if (startupSocketNotifier) { startupSocketNotifier->setEnabled(false); startupSocketNotifier->deleteLater(); @@ -732,7 +745,7 @@ bool QProcessPrivate::processStarted() // did we read an error message? if (i > 0) - q_func()->setErrorString(QString((const QChar *)buf, i / sizeof(QChar))); + q_func()->setErrorString(QString::fromLocal8Bit(buf, i)); return i <= 0; } diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index c5127944406..de4467d8975 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -2285,6 +2285,13 @@ void tst_QProcess::setNonExistentWorkingDirectory() #endif QCOMPARE(int(process->error()), int(QProcess::FailedToStart)); +#ifdef Q_OS_UNIX +# ifdef QPROCESS_USE_SPAWN + QEXPECT_FAIL("", "QProcess cannot detect failure to start when using posix_spawn()", Continue); +# endif + QVERIFY2(process->errorString().startsWith("chdir:"), process->errorString().toLocal8Bit()); +#endif + delete process; process = 0; }