QProcess/Unix: fix setting SIGPIPE to SIG_IGN where SIG_DFL was intended

And take the opportunity to clarify what the QtVforkSafe namespace is
doing. Amends commit e71c226d6f188abd811b28d3cb7529343f52d61f.

Change-Id: I443cf0c8a76243eead33fffd1767f3fa390a7cdd
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
(cherry picked from commit c4a0a76deca0bc5082fb561004bc0d29a8de9978)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2023-06-12 08:47:21 -07:00 committed by Qt Cherry-pick Bot
parent 081dd8d7f0
commit 12b43d3902
2 changed files with 19 additions and 7 deletions

View File

@ -109,7 +109,15 @@ QProcessEnvironment QProcessEnvironment::systemEnvironment()
namespace QtVforkSafe { namespace QtVforkSafe {
// Certain libc functions we need to call in the child process scenario aren't // Certain libc functions we need to call in the child process scenario aren't
// safe under vfork() because they do more than just place the system call to // safe under vfork() because they do more than just place the system call to
// the kernel and set errno on return. Those are: // the kernel and set errno on return. For those, we'll create a function
// pointer like:
// static constexpr auto foobar = __libc_foobar;
// while for all other OSes, it'll be
// using ::foobar;
// allowing the code for the child side of the vfork to simply use
// QtVforkSafe::foobar(args);
//
// Currently known issues are:
// //
// - FreeBSD's libthr sigaction() wrapper locks a rwlock // - FreeBSD's libthr sigaction() wrapper locks a rwlock
// https://github.com/freebsd/freebsd-src/blob/8dad5ece49479ba6cdcd5bb4c2799bbd61add3e6/lib/libthr/thread/thr_sig.c#L575-L641 // https://github.com/freebsd/freebsd-src/blob/8dad5ece49479ba6cdcd5bb4c2799bbd61add3e6/lib/libthr/thread/thr_sig.c#L575-L641
@ -142,11 +150,11 @@ DECLARE_FUNCTIONS(sigaction)
#undef LIBC_PREFIX #undef LIBC_PREFIX
#undef DECLARE_FUNCTIONS #undef DECLARE_FUNCTIONS
// like qt_ignore_sigpipe() in qcore_unix_p.h, but vfork-safe // similar to qt_ignore_sigpipe() in qcore_unix_p.h, but vfork-safe
static void ignore_sigpipe() static void change_sigpipe(decltype(SIG_DFL) new_handler)
{ {
struct sigaction sa; struct sigaction sa;
sa.sa_handler = SIG_IGN; sa.sa_handler = new_handler;
sigaction(SIGPIPE, &sa, nullptr); sigaction(SIGPIPE, &sa, nullptr);
} }
} // namespace QtVforkSafe } // namespace QtVforkSafe
@ -653,7 +661,7 @@ static void applyProcessParameters(const QProcess::UnixProcessParameters &params
// We don't expect signal() to fail, so we ignore its return value // We don't expect signal() to fail, so we ignore its return value
bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe); bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
if (ignore_sigpipe) if (ignore_sigpipe)
QtVforkSafe::ignore_sigpipe(); QtVforkSafe::change_sigpipe(SIG_IGN);
if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetSignalHandlers)) { if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetSignalHandlers)) {
struct sigaction sa = {}; struct sigaction sa = {};
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
@ -739,7 +747,7 @@ static const char *doExecChild(char **argv, char **envp, int workingDirFd,
// still sharing memory with the parent process. // still sharing memory with the parent process.
void QProcessPrivate::execChild(int workingDir, char **argv, char **envp) const noexcept void QProcessPrivate::execChild(int workingDir, char **argv, char **envp) const noexcept
{ {
QtVforkSafe::ignore_sigpipe(); // reset the signal that we ignored QtVforkSafe::change_sigpipe(SIG_DFL); // reset the signal that we ignored
ChildError error = { 0, {} }; // force zeroing of function[8] ChildError error = { 0, {} }; // force zeroing of function[8]
@ -1150,7 +1158,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
}(); }();
pid_t childPid = doFork(); pid_t childPid = doFork();
if (childPid == 0) { if (childPid == 0) {
QtVforkSafe::ignore_sigpipe(); // reset the signal that we ignored QtVforkSafe::change_sigpipe(SIG_DFL); // reset the signal that we ignored
::setsid(); ::setsid();
qt_safe_close(startedPipe[0]); qt_safe_close(startedPipe[0]);

View File

@ -1594,6 +1594,10 @@ void tst_QProcess::unixProcessParameters()
process.start(); process.start();
QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString())); QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString()));
QVERIFY(process.waitForFinished(5000)); QVERIFY(process.waitForFinished(5000));
#ifdef Q_OS_QNX
QEXPECT_FAIL("ignore-sigpipe", "QTBUG-114720: flag is taking no effect", Abort);
#endif
QCOMPARE(process.readAllStandardError(), QString()); QCOMPARE(process.readAllStandardError(), QString());
QCOMPARE(process.readAll(), QString()); QCOMPARE(process.readAll(), QString());
QCOMPARE(process.exitCode(), 0); QCOMPARE(process.exitCode(), 0);