diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2023-03-18 11:42:48 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2023-05-15 10:10:03 -0700 |
commit | ba05af82d3d8b7cbc6e22f93cbf1e3d1575afefe (patch) | |
tree | 16690f14548ba7eef54e6822d62e47c938ea3248 /tests | |
parent | d2242c353fac9b76437b2c3bc521c0e6e415f3b1 (diff) |
QProcess/Unix: protect against stack unwinding in the child process stub
There are two types of stack unwinding that can happen on Unix systems:
C++ exceptions and PThread cancellations (on some systems, like Linux,
PThread cancellations can be caught in catch(...) statements). We call a
variety of PThread cancellation functions from inside the child stub,
like close(). To avoid problems, we disable PThread cancellations
completely before fork() or vfork().
The C++ exception case is simpler, because we can be sure of catching
them with the catch (...) statement and simply transform them into an
error message. This is also testable, which the PThread cancellation
isn't.
The error message isn't ideal because we're string-frozen. I'll improve
it for 6.6.
Pick-to: 6.5
Change-Id: Icfe44ecf285a480fafe4fffd174d97a475c93ff1
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/corelib/io/qprocess/tst_qprocess.cpp | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index 4d54e8db27..d10c9ea566 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -112,6 +112,7 @@ private slots: #endif // Q_OS_WIN #if defined(Q_OS_UNIX) void setChildProcessModifier(); + void throwInChildProcessModifier(); #endif void exitCodeTest(); void systemEnvironment(); @@ -1469,6 +1470,34 @@ void tst_QProcess::setChildProcessModifier() QCOMPARE(process.exitStatus(), QProcess::NormalExit); QCOMPARE(process.exitCode(), 0); } + +void tst_QProcess::throwInChildProcessModifier() +{ +#ifndef __cpp_exceptions + Q_SKIP("Exceptions disabled."); +#else + QProcess process; + process.setChildProcessModifier([]() { + throw 42; + }); + process.setProgram("testProcessNormal/testProcessNormal"); + + process.start(); + QVERIFY(!process.waitForStarted(5000)); + QCOMPARE(process.state(), QProcess::NotRunning); + QCOMPARE(process.error(), QProcess::FailedToStart); + QVERIFY2(process.errorString().contains("throw"), + qPrintable(process.errorString())); + + // try again, to ensure QProcess internal state wasn't corrupted + process.start(); + QVERIFY(!process.waitForStarted(5000)); + QCOMPARE(process.state(), QProcess::NotRunning); + QCOMPARE(process.error(), QProcess::FailedToStart); + QVERIFY2(process.errorString().contains("throw"), + qPrintable(process.errorString())); +#endif +} #endif void tst_QProcess::exitCodeTest() |