QProcess/Win: do not needlessly duplicate std handles in startProcess()

The idea was to create descriptors with HANDLE_FLAG_INHERIT. However,
this can be assumed to be already the case for std descriptors, and if
it isn't, the user messed up, and we shouldn't try to work around it.

This is consistent with what we already do in startDetached().

Change-Id: I8135c5e612c361e77a0442541f2d50cfbb5b4601
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
This commit is contained in:
Alex Trotsenko 2020-12-24 17:10:33 +02:00
parent efb3d87700
commit 8be9fb66f7
2 changed files with 35 additions and 38 deletions

View File

@ -357,6 +357,7 @@ public:
void waitForDeadChild(); void waitForDeadChild();
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
STARTUPINFOW createStartupInfo();
bool callCreateProcess(QProcess::CreateProcessArguments *cpargs); bool callCreateProcess(QProcess::CreateProcessArguments *cpargs);
bool drainOutputPipes(); bool drainOutputPipes();
void flushPipeWriter(); void flushPipeWriter();

View File

@ -178,15 +178,6 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
return true; return true;
} }
static bool duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)
{
pipe[0] = INVALID_Q_PIPE;
HANDLE hStdWriteChannel = GetStdHandle(nStdHandle);
HANDLE hCurrentProcess = GetCurrentProcess();
return DuplicateHandle(hCurrentProcess, hStdWriteChannel, hCurrentProcess,
&pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
}
/* /*
Create the pipes to a QProcessPrivate::Channel. Create the pipes to a QProcessPrivate::Channel.
@ -196,30 +187,21 @@ bool QProcessPrivate::openChannel(Channel &channel)
{ {
Q_Q(QProcess); Q_Q(QProcess);
if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels) { if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels)
return DuplicateHandle(GetCurrentProcess(), stdoutChannel.pipe[1], GetCurrentProcess(), return true;
&stderrChannel.pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
}
switch (channel.type) { switch (channel.type) {
case Channel::Normal: { case Channel::Normal: {
// we're piping this channel to our own process // we're piping this channel to our own process
if (&channel == &stdinChannel) { if (&channel == &stdinChannel) {
if (inputChannelMode == QProcess::ForwardedInputChannel) { return inputChannelMode == QProcess::ForwardedInputChannel
channel.pipe[1] = INVALID_Q_PIPE; || qt_create_pipe(channel.pipe, true);
HANDLE hStdReadChannel = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hCurrentProcess = GetCurrentProcess();
return DuplicateHandle(hCurrentProcess, hStdReadChannel, hCurrentProcess,
&channel.pipe[0], 0, TRUE, DUPLICATE_SAME_ACCESS);
}
return qt_create_pipe(channel.pipe, true);
} }
if (&channel == &stdoutChannel) { if (&channel == &stdoutChannel) {
if (processChannelMode == QProcess::ForwardedChannels if (processChannelMode == QProcess::ForwardedChannels
|| processChannelMode == QProcess::ForwardedOutputChannel) { || processChannelMode == QProcess::ForwardedOutputChannel) {
return duplicateStdWriteChannel(channel.pipe, STD_OUTPUT_HANDLE); return true;
} }
if (!stdoutChannel.reader) { if (!stdoutChannel.reader) {
@ -229,7 +211,7 @@ bool QProcessPrivate::openChannel(Channel &channel)
} else /* if (&channel == &stderrChannel) */ { } else /* if (&channel == &stderrChannel) */ {
if (processChannelMode == QProcess::ForwardedChannels if (processChannelMode == QProcess::ForwardedChannels
|| processChannelMode == QProcess::ForwardedErrorChannel) { || processChannelMode == QProcess::ForwardedErrorChannel) {
return duplicateStdWriteChannel(channel.pipe, STD_ERROR_HANDLE); return true;
} }
if (!stderrChannel.reader) { if (!stderrChannel.reader) {
@ -495,6 +477,33 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e
return envlist; return envlist;
} }
static Q_PIPE pipeOrStdHandle(Q_PIPE pipe, DWORD handleNumber)
{
return pipe != INVALID_Q_PIPE ? pipe : GetStdHandle(handleNumber);
}
STARTUPINFOW QProcessPrivate::createStartupInfo()
{
Q_PIPE stdinPipe = pipeOrStdHandle(stdinChannel.pipe[0], STD_INPUT_HANDLE);
Q_PIPE stdoutPipe = pipeOrStdHandle(stdoutChannel.pipe[1], STD_OUTPUT_HANDLE);
Q_PIPE stderrPipe = stderrChannel.pipe[1];
if (stderrPipe == INVALID_Q_PIPE) {
stderrPipe = (processChannelMode == QProcess::MergedChannels)
? stdoutPipe
: GetStdHandle(STD_ERROR_HANDLE);
}
return STARTUPINFOW{
sizeof(STARTUPINFOW), 0, 0, 0,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
0, 0, 0,
STARTF_USESTDHANDLES,
0, 0, 0,
stdinPipe, stdoutPipe, stderrPipe
};
}
bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs) bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs)
{ {
if (modifyCreateProcessArgs) if (modifyCreateProcessArgs)
@ -565,15 +574,7 @@ void QProcessPrivate::startProcess()
// create new console windows (behavior consistent with UNIX). // create new console windows (behavior consistent with UNIX).
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW); DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, STARTUPINFOW startupInfo = createStartupInfo();
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
0, 0, 0,
STARTF_USESTDHANDLES,
0, 0, 0,
stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
};
const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory); const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory);
QProcess::CreateProcessArguments cpargs = { QProcess::CreateProcessArguments cpargs = {
nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())), nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
@ -908,11 +909,6 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
return true; return true;
} }
static Q_PIPE pipeOrStdHandle(Q_PIPE pipe, DWORD handleNumber)
{
return pipe != INVALID_Q_PIPE ? pipe : GetStdHandle(handleNumber);
}
bool QProcessPrivate::startDetached(qint64 *pid) bool QProcessPrivate::startDetached(qint64 *pid)
{ {
static const DWORD errorElevationRequired = 740; static const DWORD errorElevationRequired = 740;