QProcess/Unix: fix close() on invalid file descriptor

Commit 90bc0ad41f9937f9cba801b3166635f6f55e0678 ("QProcess/Unix: add
failChildProcessModifier()") added this line that set childStartedPipe
so that the failChildProcess() callback had something to write to. But
we left it set on exit from QProcessPrivate::startDetached(), which
caused the QProcess destructor to try and close it.

Noticed when debugging the issue for QTBUG-123083.

Pick-to: 6.7.0
Task-number: QTBUG-123083
Change-Id: I6818d78a57394e37857bfffd17bbc41c8400270f
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 0f56502fb6f062c6d2308198c93412c34525125b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2024-03-11 09:55:10 -07:00 committed by Qt Cherry-pick Bot
parent a7a2cf8746
commit a2d67a2671
2 changed files with 22 additions and 6 deletions

View File

@ -1290,7 +1290,6 @@ void QProcessPrivate::waitForDeadChild()
bool QProcessPrivate::startDetached(qint64 *pid) bool QProcessPrivate::startDetached(qint64 *pid)
{ {
AutoPipe startedPipe, pidPipe; AutoPipe startedPipe, pidPipe;
childStartedPipe[1] = startedPipe[1];
if (!startedPipe || !pidPipe) { if (!startedPipe || !pidPipe) {
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno)); setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false; return false;
@ -1309,6 +1308,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
return false; return false;
} }
childStartedPipe[1] = startedPipe[1]; // for failChildProcess()
pid_t childPid = childProcess.doFork([&] { pid_t childPid = childProcess.doFork([&] {
::setsid(); ::setsid();
@ -1323,6 +1323,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
qt_safe_write(pidPipe[1], &doubleForkPid, sizeof(pid_t)); qt_safe_write(pidPipe[1], &doubleForkPid, sizeof(pid_t));
return 0; return 0;
}); });
childStartedPipe[1] = -1;
int savedErrno = errno; int savedErrno = errno;
closeChannels(); closeChannels();

View File

@ -1488,6 +1488,9 @@ struct DisableCrashLogger
} }
}; };
QT_BEGIN_NAMESPACE
Q_AUTOTEST_EXPORT bool _qprocessUsingVfork() noexcept;
QT_END_NAMESPACE
static constexpr char messageFromChildProcess[] = "Message from the child process"; static constexpr char messageFromChildProcess[] = "Message from the child process";
static_assert(std::char_traits<char>::length(messageFromChildProcess) <= PIPE_BUF); static_assert(std::char_traits<char>::length(messageFromChildProcess) <= PIPE_BUF);
static void childProcessModifier(int fd) static void childProcessModifier(int fd)
@ -1499,17 +1502,28 @@ static void childProcessModifier(int fd)
void tst_QProcess::setChildProcessModifier_data() void tst_QProcess::setChildProcessModifier_data()
{ {
QTest::addColumn<bool>("detached"); QTest::addColumn<bool>("detached");
QTest::newRow("normal") << false; QTest::addColumn<bool>("useVfork");
QTest::newRow("detached") << true; QTest::newRow("normal") << false << false;
QTest::newRow("detached") << true << false;
#ifdef QT_BUILD_INTERNAL
if (_qprocessUsingVfork()) {
QTest::newRow("normal-vfork") << false << true;
QTest::newRow("detached-vfork") << true << true;
}
#endif
} }
void tst_QProcess::setChildProcessModifier() void tst_QProcess::setChildProcessModifier()
{ {
QFETCH(bool, detached); QFETCH(bool, detached);
QFETCH(bool, useVfork);
int pipes[2] = { -1 , -1 }; int pipes[2] = { -1 , -1 };
QVERIFY(qt_safe_pipe(pipes) == 0); QVERIFY(qt_safe_pipe(pipes) == 0);
QProcess process; QProcess process;
if (useVfork)
process.setUnixProcessParameters(QProcess::UnixProcessFlag::UseVFork);
process.setChildProcessModifier([pipes]() { process.setChildProcessModifier([pipes]() {
::childProcessModifier(pipes[1]); ::childProcessModifier(pipes[1]);
}); });
@ -1542,7 +1556,11 @@ void tst_QProcess::failChildProcessModifier()
"Implementation detail: the length of the message is limited"); "Implementation detail: the length of the message is limited");
QFETCH(bool, detached); QFETCH(bool, detached);
QFETCH(bool, useVfork);
QProcess process; QProcess process;
if (useVfork)
process.setUnixProcessParameters(QProcess::UnixProcessFlag::UseVFork);
process.setChildProcessModifier([&process]() { process.setChildProcessModifier([&process]() {
process.failChildProcessModifier(failureMsg, EPERM); process.failChildProcessModifier(failureMsg, EPERM);
}); });
@ -1651,9 +1669,6 @@ void tst_QProcess::terminateInChildProcessModifier()
#endif #endif
} }
QT_BEGIN_NAMESPACE
Q_AUTOTEST_EXPORT bool _qprocessUsingVfork() noexcept;
QT_END_NAMESPACE
void tst_QProcess::raiseInChildProcessModifier() void tst_QProcess::raiseInChildProcessModifier()
{ {
#ifdef QT_BUILD_INTERNAL #ifdef QT_BUILD_INTERNAL