QProcess/Unix: capture the child process modifier exception's what()
Change-Id: I5f7f427ded124479baa6fffd175ffb017b6cd13c Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
90bc0ad41f
commit
921bf4a11a
@ -641,13 +641,7 @@ void QProcessPrivate::startProcess()
|
|||||||
|
|
||||||
// we need an errno number to use to indicate the child process modifier threw,
|
// we need an errno number to use to indicate the child process modifier threw,
|
||||||
// something the regular operations shouldn't set.
|
// something the regular operations shouldn't set.
|
||||||
static constexpr int FakeErrnoForThrow =
|
static constexpr int FakeErrnoForThrow = std::numeric_limits<int>::max();
|
||||||
#ifdef ECANCELED
|
|
||||||
ECANCELED
|
|
||||||
#else
|
|
||||||
ESHUTDOWN
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
|
static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
|
||||||
{
|
{
|
||||||
@ -658,7 +652,8 @@ static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_
|
|||||||
qsizetype len = qstrnlen(err.function, sizeof(err.function));
|
qsizetype len = qstrnlen(err.function, sizeof(err.function));
|
||||||
QString complement = QString::fromUtf8(err.function, len);
|
QString complement = QString::fromUtf8(err.function, len);
|
||||||
if (err.code == FakeErrnoForThrow)
|
if (err.code == FakeErrnoForThrow)
|
||||||
return QProcess::tr("Child process modifier threw an exception");
|
return QProcess::tr("Child process modifier threw an exception: %1")
|
||||||
|
.arg(std::move(complement));
|
||||||
if (err.code == 0)
|
if (err.code == 0)
|
||||||
return QProcess::tr("Child process modifier reported error: %1")
|
return QProcess::tr("Child process modifier reported error: %1")
|
||||||
.arg(std::move(complement));
|
.arg(std::move(complement));
|
||||||
@ -732,16 +727,16 @@ static void applyProcessParameters(const QProcess::UnixProcessParameters ¶ms
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the noexcept here adds an extra layer of protection
|
// the noexcept here adds an extra layer of protection
|
||||||
static const char *callChildProcessModifier(const QProcessPrivate::UnixExtras *unixExtras) noexcept
|
static void callChildProcessModifier(const QProcessPrivate *d) noexcept
|
||||||
{
|
{
|
||||||
QT_TRY {
|
QT_TRY {
|
||||||
if (unixExtras->childProcessModifier)
|
if (d->unixExtras->childProcessModifier)
|
||||||
unixExtras->childProcessModifier();
|
d->unixExtras->childProcessModifier();
|
||||||
|
} QT_CATCH (std::exception &e) {
|
||||||
|
failChildProcess(d, e.what(), FakeErrnoForThrow);
|
||||||
} QT_CATCH (...) {
|
} QT_CATCH (...) {
|
||||||
errno = FakeErrnoForThrow;
|
failChildProcess(d, "throw", FakeErrnoForThrow);
|
||||||
return "throw";
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_NORETURN static void
|
Q_NORETURN static void
|
||||||
@ -754,8 +749,7 @@ doExecChild(char **argv, char **envp, int workingDirFd, const QProcessPrivate *d
|
|||||||
if (d->unixExtras) {
|
if (d->unixExtras) {
|
||||||
// FIRST we call the user modifier function, before we dropping
|
// FIRST we call the user modifier function, before we dropping
|
||||||
// privileges or closing non-standard file descriptors
|
// privileges or closing non-standard file descriptors
|
||||||
if (const char *what = callChildProcessModifier(d->unixExtras.get()))
|
callChildProcessModifier(d);
|
||||||
failChildProcess(d, what, FakeErrnoForThrow);
|
|
||||||
|
|
||||||
// then we apply our other user-provided parameters
|
// then we apply our other user-provided parameters
|
||||||
applyProcessParameters(d->unixExtras->processParameters);
|
applyProcessParameters(d->unixExtras->processParameters);
|
||||||
|
@ -1560,9 +1560,13 @@ void tst_QProcess::throwInChildProcessModifier()
|
|||||||
#ifndef __cpp_exceptions
|
#ifndef __cpp_exceptions
|
||||||
Q_SKIP("Exceptions disabled.");
|
Q_SKIP("Exceptions disabled.");
|
||||||
#else
|
#else
|
||||||
|
static constexpr char What[] = "tst_QProcess::throwInChildProcessModifier()::MyException";
|
||||||
|
struct MyException : std::exception {
|
||||||
|
const char *what() const noexcept override { return What; }
|
||||||
|
};
|
||||||
QProcess process;
|
QProcess process;
|
||||||
process.setChildProcessModifier([]() {
|
process.setChildProcessModifier([]() {
|
||||||
throw 42;
|
throw MyException();
|
||||||
});
|
});
|
||||||
process.setProgram("testProcessNormal/testProcessNormal");
|
process.setProgram("testProcessNormal/testProcessNormal");
|
||||||
|
|
||||||
@ -1572,6 +1576,8 @@ void tst_QProcess::throwInChildProcessModifier()
|
|||||||
QCOMPARE(process.error(), QProcess::FailedToStart);
|
QCOMPARE(process.error(), QProcess::FailedToStart);
|
||||||
QVERIFY2(process.errorString().contains("Child process modifier threw an exception"),
|
QVERIFY2(process.errorString().contains("Child process modifier threw an exception"),
|
||||||
qPrintable(process.errorString()));
|
qPrintable(process.errorString()));
|
||||||
|
QVERIFY2(process.errorString().contains(What),
|
||||||
|
qPrintable(process.errorString()));
|
||||||
|
|
||||||
// try again, to ensure QProcess internal state wasn't corrupted
|
// try again, to ensure QProcess internal state wasn't corrupted
|
||||||
process.start();
|
process.start();
|
||||||
@ -1580,6 +1586,8 @@ void tst_QProcess::throwInChildProcessModifier()
|
|||||||
QCOMPARE(process.error(), QProcess::FailedToStart);
|
QCOMPARE(process.error(), QProcess::FailedToStart);
|
||||||
QVERIFY2(process.errorString().contains("Child process modifier threw an exception"),
|
QVERIFY2(process.errorString().contains("Child process modifier threw an exception"),
|
||||||
qPrintable(process.errorString()));
|
qPrintable(process.errorString()));
|
||||||
|
QVERIFY2(process.errorString().contains(What),
|
||||||
|
qPrintable(process.errorString()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user