diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index dd3946a7443..7f2ae40ad37 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -189,6 +189,36 @@ static_assert(std::is_trivial_v); static_assert(PIPE_BUF >= sizeof(ChildError)); // PIPE_BUF may be bigger #endif +// we need an errno value to use to indicate the child process modifier threw, +// something the regular operations shouldn't set. +static constexpr int FakeErrnoForThrow = std::numeric_limits::max(); + +static QString errorMessageForSyscall(QUtf8StringView fnName, int errnoCode = -1) +{ + QString msg = qt_error_string(errnoCode); + return QProcess::tr("Child process set up failed: %1: %2").arg(fnName, std::move(msg)); +} + +static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead) +{ + // ChildError is less than the POSIX pipe buffer atomic size, so the read + // must not have been truncated + Q_ASSERT(bytesRead == sizeof(err)); + + qsizetype len = qstrnlen(err.function, sizeof(err.function)); + const QUtf8StringView complement(err.function, len); + if (err.code == FakeErrnoForThrow) + return QProcess::tr("Child process modifier threw an exception: %1") + .arg(complement); + if (err.code == 0) + return QProcess::tr("Child process modifier reported error: %1") + .arg(complement); + if (err.code < 0) + return QProcess::tr("Child process modifier reported error: %1: %2") + .arg(complement, qt_error_string(-err.code)); + return errorMessageForSyscall(complement, err.code); +} + struct QProcessPoller { QProcessPoller(const QProcessPrivate &proc); @@ -262,7 +292,7 @@ struct QChildProcess if (!d->workingDirectory.isEmpty()) { workingDirectory = opendirfd(QFile::encodeName(d->workingDirectory)); if (workingDirectory < 0) { - d->setErrorAndEmit(QProcess::FailedToStart, "chdir: "_L1 + qt_error_string()); + d->setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("chdir")); d->cleanup(); // make sure our destructor does nothing @@ -491,7 +521,7 @@ bool QProcessPrivate::openChannel(Channel &channel) if (channel.type == Channel::Normal) { // we're piping this channel to our own process if (qt_create_pipe(channel.pipe) != 0) { - setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); + setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe")); return false; } @@ -573,7 +603,7 @@ bool QProcessPrivate::openChannel(Channel &channel) Q_PIPE pipe[2] = { -1, -1 }; if (qt_create_pipe(pipe) != 0) { - setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); + setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe")); return false; } sink->pipe[0] = pipe[0]; @@ -708,7 +738,7 @@ void QProcessPrivate::startProcess() return; } if (qt_create_pipe(childStartedPipe) != 0) { - setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); + setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe")); cleanup(); return; } @@ -778,31 +808,6 @@ void QProcessPrivate::startProcess() ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK); } -// we need an errno number to use to indicate the child process modifier threw, -// something the regular operations shouldn't set. -static constexpr int FakeErrnoForThrow = std::numeric_limits::max(); - -static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead) -{ - // ChildError is less than the POSIX pipe buffer atomic size, so the read - // must not have been truncated - Q_ASSERT(bytesRead == sizeof(err)); - - qsizetype len = qstrnlen(err.function, sizeof(err.function)); - const QUtf8StringView complement(err.function, len); - if (err.code == FakeErrnoForThrow) - return QProcess::tr("Child process modifier threw an exception: %1") - .arg(complement); - if (err.code == 0) - return QProcess::tr("Child process modifier reported error: %1") - .arg(complement); - if (err.code < 0) - return QProcess::tr("Child process modifier reported error: %1: %2") - .arg(complement, qt_error_string(-err.code)); - return QProcess::tr("Child process set up failed: %1: %2") - .arg(complement, qt_error_string(err.code)); -} - Q_NORETURN void failChildProcess(const QProcessPrivate *d, const char *description, int code) noexcept { @@ -1320,7 +1325,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) { AutoPipe startedPipe, pidPipe; if (!startedPipe || !pidPipe) { - setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); + setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe")); return false; } @@ -1359,7 +1364,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) if (childPid == -1) { childProcess.cleanup(); - setErrorAndEmit(QProcess::FailedToStart, "fork: "_L1 + qt_error_string(savedErrno)); + setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("fork", savedErrno)); return false; } diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index 557eda3e6ca..5e9651347a4 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -2884,7 +2884,8 @@ void tst_QProcess::detachedSetNonExistentWorkingDirectory() QCOMPARE(process.error(), QProcess::FailedToStart); #ifdef Q_OS_UNIX - QVERIFY2(process.errorString().startsWith("chdir:"), process.errorString().toLocal8Bit()); + QVERIFY2(process.errorString().contains(": chdir: "), process.errorString().toLocal8Bit()); + QVERIFY2(process.errorString().contains(qt_error_string(ENOENT)), process.errorString().toLocal8Bit()); #endif }