mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-05 16:55:25 +08:00
qt 6.6.0 clean
This commit is contained in:
@ -28,3 +28,6 @@ if(WIN32)
|
||||
add_subdirectory(testProcessEchoGui)
|
||||
add_subdirectory(testSetNamedPipeHandleState)
|
||||
endif()
|
||||
if(UNIX)
|
||||
add_subdirectory(testUnixProcessParameters)
|
||||
endif()
|
||||
|
58
tests/auto/corelib/io/qprocess/crasher.h
Normal file
58
tests/auto/corelib/io/qprocess/crasher.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2020 Intel Corporation.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
#if __has_include(<signal.h>)
|
||||
# include <signal.h>
|
||||
#endif
|
||||
#if __has_include(<sys/resource.h>)
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
namespace tst_QProcessCrash {
|
||||
struct NoCoreDumps
|
||||
{
|
||||
#if defined(RLIMIT_CORE)
|
||||
struct rlimit rlim;
|
||||
NoCoreDumps()
|
||||
{
|
||||
if (getrlimit(RLIMIT_CORE, &rlim) == 0 && rlim.rlim_cur != 0) {
|
||||
struct rlimit newrlim = rlim;
|
||||
newrlim.rlim_cur = 0;
|
||||
setrlimit(RLIMIT_CORE, &newrlim);
|
||||
}
|
||||
}
|
||||
~NoCoreDumps()
|
||||
{
|
||||
setrlimit(RLIMIT_CORE, &rlim);
|
||||
}
|
||||
#endif // RLIMIT_CORE
|
||||
};
|
||||
|
||||
void crashFallback(volatile int *ptr = nullptr)
|
||||
{
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
void crash()
|
||||
{
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||
__ud2();
|
||||
#elif __has_builtin(__builtin_trap)
|
||||
__builtin_trap();
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
asm("ud2");
|
||||
#elif defined(SIGILL)
|
||||
raise(SIGILL);
|
||||
#endif
|
||||
|
||||
crashFallback();
|
||||
}
|
||||
} // namespace tst_QProcessCrash
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testExitCodes
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -13,7 +13,7 @@ static bool waitForDoneFileWritten(const QString &filePath, int msecs = 30000)
|
||||
{
|
||||
QDeadlineTimer t(msecs);
|
||||
do {
|
||||
QThread::msleep(250);
|
||||
QThread::sleep(std::chrono::milliseconds{250});
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
continue;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testForwardingHelper
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessCrash
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -2,49 +2,12 @@
|
||||
// Copyright (C) 2020 Intel Corporation.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#if __has_include(<sys/resource.h>)
|
||||
# include <sys/resource.h>
|
||||
# if defined(RLIMIT_CORE)
|
||||
static bool disableCoreDumps()
|
||||
{
|
||||
// Unix: set our core dump limit to zero to request no dialogs.
|
||||
if (struct rlimit rlim; getrlimit(RLIMIT_CORE, &rlim) == 0) {
|
||||
rlim.rlim_cur = 0;
|
||||
setrlimit(RLIMIT_CORE, &rlim);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool disabledCoreDumps = disableCoreDumps();
|
||||
# endif // RLIMIT_CORE
|
||||
#endif // <sys/resource.h>
|
||||
|
||||
void crashFallback(volatile int *ptr = nullptr)
|
||||
{
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#include "../crasher.h"
|
||||
using namespace tst_QProcessCrash;
|
||||
|
||||
int main()
|
||||
{
|
||||
# if defined(_M_IX86) || defined(_M_X64)
|
||||
__ud2();
|
||||
# endif
|
||||
|
||||
crashFallback();
|
||||
NoCoreDumps disableCoreDumps;
|
||||
crash();
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__MINGW32__)
|
||||
int main()
|
||||
{
|
||||
asm("ud2");
|
||||
crashFallback();
|
||||
}
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessDeadWhileReading
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessEOF
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessEcho
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessEcho2
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessEcho3
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -8,6 +8,7 @@
|
||||
qt_internal_add_executable(testProcessEchoGui
|
||||
GUI
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main_win.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessEnvironment
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessHang
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessNormal
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testProcessOutput
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -3,12 +3,14 @@
|
||||
|
||||
qt_internal_add_executable(nospace
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_internal_add_executable(onespace
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
@ -16,6 +18,7 @@ set_target_properties(onespace PROPERTIES OUTPUT_NAME "one space")
|
||||
|
||||
qt_internal_add_executable(twospaces
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testSetNamedPipeHandleState
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testSoftExit
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
)
|
||||
|
||||
qt_internal_extend_target(testSoftExit CONDITION WIN32
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
qt_internal_add_executable(testSpaceInName
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2023 Intel Corporation.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## testProcessNormal Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_executable(testUnixProcessParameters
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
CORE_LIBRARY None
|
||||
SOURCES
|
||||
main.cpp
|
||||
)
|
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2023 Intel Corporation.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s command [extra]\nSee source code for commands\n",
|
||||
argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string_view cmd = argv[1];
|
||||
errno = 0;
|
||||
|
||||
if (cmd.size() == 0) {
|
||||
// just checking that we did get here
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (cmd == "reset-sighand") {
|
||||
bool ok = true;
|
||||
|
||||
// confirm our signal block mask is empty
|
||||
sigset_t set;
|
||||
sigprocmask(SIG_SETMASK, nullptr, &set);
|
||||
for (int signo = 1; signo < NSIG; ++signo) {
|
||||
if (sigismember(&set, signo)) {
|
||||
fprintf(stderr, "'%s' is blocked.\n", strsignal(signo));
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
// confirm SIGUSR1 was not ignored
|
||||
struct sigaction action;
|
||||
sigaction(SIGUSR1, nullptr, &action);
|
||||
if (action.sa_handler != SIG_DFL) {
|
||||
fprintf(stderr, "SIGUSR1 is SIG_IGN\n");
|
||||
ok = false;
|
||||
}
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (cmd == "ignore-sigpipe") {
|
||||
// confirm SIGPIPE was ignored
|
||||
struct sigaction action;
|
||||
sigaction(SIGPIPE, nullptr, &action);
|
||||
if (action.sa_handler == SIG_IGN)
|
||||
return EXIT_SUCCESS;
|
||||
fprintf(stderr, "SIGPIPE is SIG_DFL\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (cmd == "file-descriptors") {
|
||||
int fd = atoi(argv[2]);
|
||||
if (close(fd) < 0 && errno == EBADF)
|
||||
return EXIT_SUCCESS;
|
||||
fprintf(stderr, "%d is a valid file descriptor\n", fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (cmd == "file-descriptors2") {
|
||||
int fd1 = atoi(argv[2]); // should be open
|
||||
int fd2 = atoi(argv[3]); // should be closed
|
||||
if (close(fd1) < 0)
|
||||
fprintf(stderr, "%d was not a valid file descriptor\n", fd1);
|
||||
if (close(fd2) == 0 || errno != EBADF)
|
||||
fprintf(stderr, "%d is a valid file descriptor\n", fd2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unknown command \"%s\"", cmd.data());
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
#include <qplatformdefs.h>
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <private/qcore_unix_p.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <QtTest/private/qemulationdetector_p.h>
|
||||
@ -111,7 +112,13 @@ private slots:
|
||||
void createProcessArgumentsModifier();
|
||||
#endif // Q_OS_WIN
|
||||
#if defined(Q_OS_UNIX)
|
||||
void setChildProcessModifier_data();
|
||||
void setChildProcessModifier();
|
||||
void throwInChildProcessModifier();
|
||||
void unixProcessParameters_data();
|
||||
void unixProcessParameters();
|
||||
void unixProcessParametersAndChildModifier();
|
||||
void unixProcessParametersOtherFileDescriptors();
|
||||
#endif
|
||||
void exitCodeTest();
|
||||
void systemEnvironment();
|
||||
@ -152,6 +159,7 @@ protected slots:
|
||||
private:
|
||||
qint64 bytesAvailable;
|
||||
QTemporaryDir m_temporaryDir;
|
||||
bool haveWorkingVFork = false;
|
||||
};
|
||||
|
||||
void tst_QProcess::initTestCase()
|
||||
@ -163,6 +171,12 @@ void tst_QProcess::initTestCase()
|
||||
// chdir to our testdata path and execute helper apps relative to that.
|
||||
QString testdata_dir = QFileInfo(QFINDTESTDATA("testProcessNormal")).absolutePath();
|
||||
QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir));
|
||||
|
||||
#if defined(Q_OS_LINUX) && QT_CONFIG(forkfd_pidfd)
|
||||
// see detect_clone_pidfd_support() in forkfd_linux.c for explanation
|
||||
waitid(/*P_PIDFD*/ idtype_t(3), INT_MAX, NULL, WEXITED|WNOHANG);
|
||||
haveWorkingVFork = (errno == EBADF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QProcess::cleanupTestCase()
|
||||
@ -1445,8 +1459,16 @@ static void childProcessModifier(int fd)
|
||||
QT_CLOSE(fd);
|
||||
}
|
||||
|
||||
void tst_QProcess::setChildProcessModifier_data()
|
||||
{
|
||||
QTest::addColumn<bool>("detached");
|
||||
QTest::newRow("normal") << false;
|
||||
QTest::newRow("detached") << true;
|
||||
}
|
||||
|
||||
void tst_QProcess::setChildProcessModifier()
|
||||
{
|
||||
QFETCH(bool, detached);
|
||||
int pipes[2] = { -1 , -1 };
|
||||
QVERIFY(qt_safe_pipe(pipes) == 0);
|
||||
|
||||
@ -1454,20 +1476,215 @@ void tst_QProcess::setChildProcessModifier()
|
||||
process.setChildProcessModifier([pipes]() {
|
||||
::childProcessModifier(pipes[1]);
|
||||
});
|
||||
process.start("testProcessNormal/testProcessNormal");
|
||||
if (process.state() != QProcess::Starting)
|
||||
QCOMPARE(process.state(), QProcess::Running);
|
||||
QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString()));
|
||||
process.setProgram("testProcessNormal/testProcessNormal");
|
||||
if (detached) {
|
||||
process.startDetached();
|
||||
} else {
|
||||
process.start("testProcessNormal/testProcessNormal");
|
||||
if (process.state() != QProcess::Starting)
|
||||
QCOMPARE(process.state(), QProcess::Running);
|
||||
QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString()));
|
||||
QVERIFY2(process.waitForFinished(5000), qPrintable(process.errorString()));
|
||||
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
||||
QCOMPARE(process.exitCode(), 0);
|
||||
}
|
||||
|
||||
char buf[sizeof messageFromChildProcess] = {};
|
||||
qt_safe_close(pipes[1]);
|
||||
QCOMPARE(qt_safe_read(pipes[0], buf, sizeof(buf)), qint64(sizeof(messageFromChildProcess)) - 1);
|
||||
QCOMPARE(buf, messageFromChildProcess);
|
||||
qt_safe_close(pipes[0]);
|
||||
}
|
||||
|
||||
QVERIFY2(process.waitForFinished(5000), qPrintable(process.errorString()));
|
||||
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
||||
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("childProcessModifier"),
|
||||
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("childProcessModifier"),
|
||||
qPrintable(process.errorString()));
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QProcess::unixProcessParameters_data()
|
||||
{
|
||||
QTest::addColumn<QProcess::UnixProcessParameters>("params");
|
||||
QTest::addColumn<QString>("cmd");
|
||||
QTest::newRow("defaults") << QProcess::UnixProcessParameters{} << QString();
|
||||
|
||||
auto addRow = [](const char *cmd, QProcess::UnixProcessFlags flags) {
|
||||
QProcess::UnixProcessParameters params = {};
|
||||
params.flags = flags;
|
||||
QTest::addRow("%s", cmd) << params << cmd;
|
||||
};
|
||||
using P = QProcess::UnixProcessFlag;
|
||||
addRow("reset-sighand", P::ResetSignalHandlers);
|
||||
addRow("ignore-sigpipe", P::IgnoreSigPipe);
|
||||
addRow("file-descriptors", P::CloseFileDescriptors);
|
||||
}
|
||||
|
||||
void tst_QProcess::unixProcessParameters()
|
||||
{
|
||||
QFETCH(QProcess::UnixProcessParameters, params);
|
||||
QFETCH(QString, cmd);
|
||||
|
||||
// set up a few things
|
||||
struct Scope {
|
||||
int devnull;
|
||||
struct sigaction old_sigusr1, old_sigpipe;
|
||||
Scope()
|
||||
{
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
devnull = fcntl(fd, F_DUPFD, 100);
|
||||
close(fd);
|
||||
|
||||
// we ignore SIGUSR1 and reset SIGPIPE to Terminate
|
||||
struct sigaction act = {};
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction(SIGUSR1, &act, &old_sigusr1);
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction(SIGPIPE, &act, &old_sigpipe);
|
||||
|
||||
// and we block SIGUSR2
|
||||
sigset_t *set = &act.sa_mask; // reuse this sigset_t
|
||||
sigaddset(set, SIGUSR2);
|
||||
sigprocmask(SIG_BLOCK, set, nullptr);
|
||||
}
|
||||
~Scope()
|
||||
{
|
||||
if (devnull != -1)
|
||||
dismiss();
|
||||
}
|
||||
void dismiss()
|
||||
{
|
||||
close(devnull);
|
||||
sigaction(SIGUSR1, &old_sigusr1, nullptr);
|
||||
sigaction(SIGPIPE, &old_sigpipe, nullptr);
|
||||
devnull = -1;
|
||||
|
||||
sigset_t *set = &old_sigusr1.sa_mask; // reuse this sigset_t
|
||||
sigaddset(set, SIGUSR2);
|
||||
sigprocmask(SIG_BLOCK, set, nullptr);
|
||||
}
|
||||
} scope;
|
||||
|
||||
QProcess process;
|
||||
process.setUnixProcessParameters(params);
|
||||
process.setStandardInputFile(QProcess::nullDevice()); // so we can't mess with SIGPIPE
|
||||
process.setProgram("testUnixProcessParameters/testUnixProcessParameters");
|
||||
process.setArguments({ cmd, QString::number(scope.devnull) });
|
||||
process.start();
|
||||
QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString()));
|
||||
QVERIFY(process.waitForFinished(5000));
|
||||
|
||||
const QString stdErr = process.readAllStandardError();
|
||||
QCOMPARE(stdErr, QString());
|
||||
QCOMPARE(process.readAll(), QString());
|
||||
QCOMPARE(process.exitCode(), 0);
|
||||
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
||||
}
|
||||
|
||||
void tst_QProcess::unixProcessParametersAndChildModifier()
|
||||
{
|
||||
static constexpr char message[] = "Message from the handler function\n";
|
||||
static_assert(std::char_traits<char>::length(message) <= PIPE_BUF);
|
||||
QProcess process;
|
||||
QAtomicInt vforkControl;
|
||||
int pipes[2];
|
||||
|
||||
QVERIFY2(pipe(pipes) == 0, qPrintable(qt_error_string()));
|
||||
auto pipeGuard0 = qScopeGuard([=] { close(pipes[0]); });
|
||||
{
|
||||
auto pipeGuard1 = qScopeGuard([=] { close(pipes[1]); });
|
||||
|
||||
// verify that our modifier runs before the parameters are applied
|
||||
process.setChildProcessModifier([=, &vforkControl] {
|
||||
write(pipes[1], message, strlen(message));
|
||||
vforkControl.storeRelaxed(1);
|
||||
});
|
||||
auto flags = QProcess::UnixProcessFlag::CloseFileDescriptors |
|
||||
QProcess::UnixProcessFlag::UseVFork;
|
||||
process.setUnixProcessParameters({ flags });
|
||||
process.setProgram("testUnixProcessParameters/testUnixProcessParameters");
|
||||
process.setArguments({ "file-descriptors", QString::number(pipes[1]) });
|
||||
process.start();
|
||||
QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString()));
|
||||
} // closes the writing end of the pipe
|
||||
|
||||
QVERIFY(process.waitForFinished(5000));
|
||||
QCOMPARE(process.readAllStandardError(), QString());
|
||||
QCOMPARE(process.readAll(), QString());
|
||||
|
||||
char buf[2 * sizeof(message)];
|
||||
int r = read(pipes[0], buf, sizeof(buf));
|
||||
QVERIFY2(r >= 0, qPrintable(qt_error_string()));
|
||||
QCOMPARE(QByteArrayView(buf, r), message);
|
||||
|
||||
if (haveWorkingVFork)
|
||||
QVERIFY2(vforkControl.loadRelaxed(), "QProcess doesn't appear to have used vfork()");
|
||||
}
|
||||
|
||||
void tst_QProcess::unixProcessParametersOtherFileDescriptors()
|
||||
{
|
||||
constexpr int TargetFileDescriptor = 3;
|
||||
int pipes[2];
|
||||
int fd1 = open("/dev/null", O_RDONLY);
|
||||
int devnull = fcntl(fd1, F_DUPFD, 100); // instead of F_DUPFD_CLOEXEC
|
||||
qt_safe_pipe(pipes); // implied O_CLOEXEC
|
||||
close(fd1);
|
||||
|
||||
auto closeFds = qScopeGuard([&] {
|
||||
close(devnull);
|
||||
close(pipes[0]);
|
||||
// we'll close pipe[1] before any QCOMPARE
|
||||
});
|
||||
|
||||
QProcess process;
|
||||
QProcess::UnixProcessParameters params;
|
||||
params.flags = QProcess::UnixProcessFlag::CloseFileDescriptors
|
||||
| QProcess::UnixProcessFlag::UseVFork;
|
||||
params.lowestFileDescriptorToClose = 4;
|
||||
process.setUnixProcessParameters(params);
|
||||
process.setChildProcessModifier([devnull, pipes]() {
|
||||
if (dup2(devnull, TargetFileDescriptor) == TargetFileDescriptor)
|
||||
return;
|
||||
write(pipes[1], &errno, sizeof(errno));
|
||||
_exit(255);
|
||||
});
|
||||
process.setProgram("testUnixProcessParameters/testUnixProcessParameters");
|
||||
process.setArguments({ "file-descriptors2", QString::number(TargetFileDescriptor),
|
||||
QString::number(devnull) });
|
||||
process.start();
|
||||
close(pipes[1]);
|
||||
|
||||
if (int duperror; read(pipes[0], &duperror, sizeof(duperror)) == sizeof(duperror))
|
||||
QFAIL(QByteArray("dup2 failed: ") + strerror(duperror));
|
||||
|
||||
QVERIFY2(process.waitForStarted(5000), qPrintable(process.errorString()));
|
||||
QVERIFY(process.waitForFinished(5000));
|
||||
QCOMPARE(process.readAllStandardError(), QString());
|
||||
QCOMPARE(process.readAll(), QString());
|
||||
QCOMPARE(process.exitCode(), 0);
|
||||
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1500,7 +1717,7 @@ void tst_QProcess::failToStart()
|
||||
// to many processes here will cause test failures later on.
|
||||
#if defined Q_OS_HPUX
|
||||
const int attempts = 15;
|
||||
#elif defined Q_OS_MAC
|
||||
#elif defined Q_OS_DARWIN
|
||||
const int attempts = 15;
|
||||
#else
|
||||
const int attempts = 50;
|
||||
@ -2362,7 +2579,7 @@ public:
|
||||
public slots:
|
||||
void block()
|
||||
{
|
||||
QThread::sleep(1);
|
||||
QThread::sleep(std::chrono::seconds{1});
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user