diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 0f6ac95a895..9093cf1e75f 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -521,7 +521,6 @@ bool QProcessPrivate::openChannel(Channel &channel) setErrorAndEmit(QProcess::FailedToStart, QProcess::tr("Could not open input redirection for reading")); } - cleanup(); return false; } else { Q_ASSERT_X(channel.process, "QProcess::start", "Internal error"); @@ -673,6 +672,7 @@ Q_AUTOTEST_EXPORT bool _qprocessUsingVfork() noexcept void QProcessPrivate::startProcess() { Q_Q(QProcess); + q->setProcessState(QProcess::Starting); #if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::startProcess()"); @@ -681,6 +681,8 @@ void QProcessPrivate::startProcess() // Initialize pipes if (!openChannels()) { // openChannel sets the error string + Q_ASSERT(!errorString.isEmpty()); + cleanup(); return; } if (qt_create_pipe(childStartedPipe) != 0) { @@ -707,7 +709,6 @@ void QProcessPrivate::startProcess() } // Start the child. - q->setProcessState(QProcess::Starting); forkfd = childProcess.startChild(&pid); int lastForkErrno = errno; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 650e9038cc5..9b1ac1ca3ae 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -265,7 +265,6 @@ bool QProcessPrivate::openChannel(Channel &channel) setErrorAndEmit(QProcess::FailedToStart, QProcess::tr("Could not open output redirection for writing")); } - cleanup(); return false; } case Channel::PipeSource: { @@ -523,9 +522,9 @@ void QProcessPrivate::startProcess() q->setProcessState(QProcess::Starting); if (!openChannels()) { - QString errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string()); + // openChannel sets the error string + Q_ASSERT(!errorString.isEmpty()); cleanup(); - setErrorAndEmit(QProcess::FailedToStart, errorString); return; } diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index 37a503c670f..6a8ea644e12 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -88,8 +88,11 @@ private slots: void environmentIsSorted(); void spaceInName(); void setStandardInputFile(); + void setStandardInputFileFailure(); void setStandardOutputFile_data(); void setStandardOutputFile(); + void setStandardOutputFileFailure_data() { setStandardOutputFile_data(); } + void setStandardOutputFileFailure(); void setStandardOutputFileNullDevice(); void setStandardOutputFileAndWaitForBytesWritten(); void setStandardOutputProcess_data(); @@ -168,6 +171,8 @@ protected slots: void waitForBytesWrittenInABytesWrittenSlotSlot(); private: + QString nonExistentFileName = u"/this/file/cant/exist/hopefully"_s; + qint64 bytesAvailable; QTemporaryDir m_temporaryDir; bool haveWorkingVFork = false; @@ -2319,12 +2324,21 @@ void tst_QProcess::setStandardInputFile() QProcess process; QFile file(m_temporaryDir.path() + QLatin1String("/data-sif")); + QSignalSpy stateSpy(&process, &QProcess::stateChanged); + QSignalSpy errorOccurredSpy(&process, &QProcess::errorOccurred); + QVERIFY(file.open(QIODevice::WriteOnly)); file.write(data, sizeof data); file.close(); process.setStandardInputFile(file.fileName()); process.start("testProcessEcho/testProcessEcho"); + QVERIFY(process.waitForStarted()); + QCOMPARE(errorOccurredSpy.size(), 0); + QCOMPARE(stateSpy.size(), 2); + QCOMPARE(stateSpy[0][0].value(), QProcess::Starting); + QCOMPARE(stateSpy[1][0].value(), QProcess::Running); + stateSpy.clear(); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); @@ -2341,6 +2355,25 @@ void tst_QProcess::setStandardInputFile() QCOMPARE(all.size(), 0); } +void tst_QProcess::setStandardInputFileFailure() +{ + QProcess process; + process.setStandardInputFile(nonExistentFileName); + + QSignalSpy stateSpy(&process, &QProcess::stateChanged); + QSignalSpy errorOccurredSpy(&process, &QProcess::errorOccurred); + + process.start("testProcessEcho/testProcessEcho"); + QVERIFY(!process.waitForStarted()); + + QCOMPARE(errorOccurredSpy.size(), 1); + QCOMPARE(errorOccurredSpy[0][0].value(), QProcess::FailedToStart); + + QCOMPARE(stateSpy.size(), 2); + QCOMPARE(stateSpy[0][0].value(), QProcess::Starting); + QCOMPARE(stateSpy[1][0].value(), QProcess::NotRunning); +} + void tst_QProcess::setStandardOutputFile_data() { QTest::addColumn("channelToTest"); @@ -2394,7 +2427,17 @@ void tst_QProcess::setStandardOutputFile() else process.setStandardErrorFile(file.fileName(), mode); + QSignalSpy stateSpy(&process, &QProcess::stateChanged); + QSignalSpy errorOccurredSpy(&process, &QProcess::errorOccurred); + process.start("testProcessEcho2/testProcessEcho2"); + QVERIFY(process.waitForStarted()); + QCOMPARE(errorOccurredSpy.size(), 0); + QCOMPARE(stateSpy.size(), 2); + QCOMPARE(stateSpy[0][0].value(), QProcess::Starting); + QCOMPARE(stateSpy[1][0].value(), QProcess::Running); + stateSpy.clear(); + process.write(testdata, sizeof testdata); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); @@ -2419,6 +2462,34 @@ void tst_QProcess::setStandardOutputFile() QCOMPARE(all.size(), expectedsize); } +void tst_QProcess::setStandardOutputFileFailure() +{ + QFETCH(QProcess::ProcessChannel, channelToTest); + QFETCH(QProcess::ProcessChannelMode, channelMode); + QFETCH(bool, append); + + QIODevice::OpenMode mode = append ? QIODevice::Append : QIODevice::Truncate; + + // run the process + QProcess process; + process.setProcessChannelMode(channelMode); + if (channelToTest == QProcess::StandardOutput) + process.setStandardOutputFile(nonExistentFileName, mode); + else + process.setStandardErrorFile(nonExistentFileName, mode); + + QSignalSpy stateSpy(&process, &QProcess::stateChanged); + QSignalSpy errorOccurredSpy(&process, &QProcess::errorOccurred); + + process.start("testProcessEcho2/testProcessEcho2"); + QVERIFY(!process.waitForStarted()); + QCOMPARE(errorOccurredSpy.size(), 1); + QCOMPARE(errorOccurredSpy[0][0].value(), QProcess::FailedToStart); + QCOMPARE(stateSpy.size(), 2); + QCOMPARE(stateSpy[0][0].value(), QProcess::Starting); + QCOMPARE(stateSpy[1][0].value(), QProcess::NotRunning); +} + void tst_QProcess::setStandardOutputFileNullDevice() { static const char testdata[] = "Test data."; @@ -2694,13 +2765,21 @@ void tst_QProcess::setWorkingDirectory() void tst_QProcess::setNonExistentWorkingDirectory() { QProcess process; - process.setWorkingDirectory("this/directory/should/not/exist/for/sure"); + process.setWorkingDirectory(nonExistentFileName); + + QSignalSpy stateSpy(&process, &QProcess::stateChanged); + QSignalSpy errorOccurredSpy(&process, &QProcess::errorOccurred); // use absolute path because on Windows, the executable is relative to the parent's CWD // while on Unix with fork it's relative to the child's (with posix_spawn, it could be either). process.start(QFileInfo("testSetWorkingDirectory/testSetWorkingDirectory").absoluteFilePath()); + QVERIFY(!process.waitForFinished()); - QCOMPARE(int(process.error()), int(QProcess::FailedToStart)); + QCOMPARE(errorOccurredSpy.size(), 1); + QCOMPARE(process.error(), QProcess::FailedToStart); + QCOMPARE(stateSpy.size(), 2); + QCOMPARE(stateSpy[0][0].value(), QProcess::Starting); + QCOMPARE(stateSpy[1][0].value(), QProcess::NotRunning); #ifdef Q_OS_UNIX QVERIFY2(process.errorString().startsWith("chdir:"), process.errorString().toLocal8Bit()); @@ -2710,7 +2789,9 @@ void tst_QProcess::setNonExistentWorkingDirectory() void tst_QProcess::detachedSetNonExistentWorkingDirectory() { QProcess process; - process.setWorkingDirectory("this/directory/should/not/exist/for/sure"); + process.setWorkingDirectory(nonExistentFileName); + + QSignalSpy errorOccurredSpy(&process, &QProcess::errorOccurred); // use absolute path because on Windows, the executable is relative to the parent's CWD // while on Unix with fork it's relative to the child's (with posix_spawn, it could be either). @@ -2722,6 +2803,9 @@ void tst_QProcess::detachedSetNonExistentWorkingDirectory() QCOMPARE(process.error(), QProcess::FailedToStart); QVERIFY(process.errorString() != "Unknown error"); + QCOMPARE(errorOccurredSpy.size(), 1); + QCOMPARE(process.error(), QProcess::FailedToStart); + #ifdef Q_OS_UNIX QVERIFY2(process.errorString().startsWith("chdir:"), process.errorString().toLocal8Bit()); #endif