QProcess/Win: handle more errors in openChannel()
In theory, low-level functions like CreateNamedPipe() or DuplicateHandle() could suddenly fail. Thus, in order to ensure the correct configuration of the channels, we must check for these errors. Change-Id: I3d6291043e5e394ec5c5a7d85dfb7b09bfdcd172 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit efb3d87700fc057db1e2374c7cf5717df6dc68b8) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
dbfd3d2892
commit
d80faf24d7
@ -86,7 +86,7 @@ QProcessEnvironment QProcessEnvironment::systemEnvironment()
|
|||||||
|
|
||||||
#if QT_CONFIG(process)
|
#if QT_CONFIG(process)
|
||||||
|
|
||||||
static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
||||||
{
|
{
|
||||||
// Anomymous pipes do not support asynchronous I/O. Thus we
|
// Anomymous pipes do not support asynchronous I/O. Thus we
|
||||||
// create named pipes for redirecting stdout, stderr and stdin.
|
// create named pipes for redirecting stdout, stderr and stdin.
|
||||||
@ -128,7 +128,7 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
|||||||
DWORD dwError = GetLastError();
|
DWORD dwError = GetLastError();
|
||||||
if (dwError != ERROR_PIPE_BUSY || !--attempts) {
|
if (dwError != ERROR_PIPE_BUSY || !--attempts) {
|
||||||
qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.");
|
qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
|||||||
if (hClient == INVALID_HANDLE_VALUE) {
|
if (hClient == INVALID_HANDLE_VALUE) {
|
||||||
qErrnoWarning("QProcess: CreateFile failed.");
|
qErrnoWarning("QProcess: CreateFile failed.");
|
||||||
CloseHandle(hServer);
|
CloseHandle(hServer);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until connection is in place.
|
// Wait until connection is in place.
|
||||||
@ -164,7 +164,7 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
|||||||
CloseHandle(overlapped.hEvent);
|
CloseHandle(overlapped.hEvent);
|
||||||
CloseHandle(hClient);
|
CloseHandle(hClient);
|
||||||
CloseHandle(hServer);
|
CloseHandle(hServer);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(overlapped.hEvent);
|
CloseHandle(overlapped.hEvent);
|
||||||
@ -176,15 +176,16 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
|
|||||||
pipe[0] = hServer;
|
pipe[0] = hServer;
|
||||||
pipe[1] = hClient;
|
pipe[1] = hClient;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)
|
static bool duplicateStdWriteChannel(Q_PIPE *pipe, DWORD nStdHandle)
|
||||||
{
|
{
|
||||||
pipe[0] = INVALID_Q_PIPE;
|
pipe[0] = INVALID_Q_PIPE;
|
||||||
HANDLE hStdWriteChannel = GetStdHandle(nStdHandle);
|
HANDLE hStdWriteChannel = GetStdHandle(nStdHandle);
|
||||||
HANDLE hCurrentProcess = GetCurrentProcess();
|
HANDLE hCurrentProcess = GetCurrentProcess();
|
||||||
DuplicateHandle(hCurrentProcess, hStdWriteChannel, hCurrentProcess,
|
return DuplicateHandle(hCurrentProcess, hStdWriteChannel, hCurrentProcess,
|
||||||
&pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
|
&pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -202,47 +203,48 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (inputChannelMode == QProcess::ForwardedInputChannel) {
|
||||||
qt_create_pipe(channel.pipe, true);
|
|
||||||
} else {
|
|
||||||
channel.pipe[1] = INVALID_Q_PIPE;
|
channel.pipe[1] = INVALID_Q_PIPE;
|
||||||
HANDLE hStdReadChannel = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE hStdReadChannel = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
HANDLE hCurrentProcess = GetCurrentProcess();
|
HANDLE hCurrentProcess = GetCurrentProcess();
|
||||||
DuplicateHandle(hCurrentProcess, hStdReadChannel, hCurrentProcess,
|
return DuplicateHandle(hCurrentProcess, hStdReadChannel, hCurrentProcess,
|
||||||
&channel.pipe[0], 0, TRUE, DUPLICATE_SAME_ACCESS);
|
&channel.pipe[0], 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (&channel == &stdoutChannel) {
|
return qt_create_pipe(channel.pipe, true);
|
||||||
if (processChannelMode != QProcess::ForwardedChannels
|
}
|
||||||
&& processChannelMode != QProcess::ForwardedOutputChannel) {
|
|
||||||
if (!stdoutChannel.reader) {
|
if (&channel == &stdoutChannel) {
|
||||||
stdoutChannel.reader = new QWindowsPipeReader(q);
|
if (processChannelMode == QProcess::ForwardedChannels
|
||||||
q->connect(stdoutChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput()));
|
|| processChannelMode == QProcess::ForwardedOutputChannel) {
|
||||||
}
|
return duplicateStdWriteChannel(channel.pipe, STD_OUTPUT_HANDLE);
|
||||||
} else {
|
|
||||||
duplicateStdWriteChannel(channel.pipe, STD_OUTPUT_HANDLE);
|
|
||||||
}
|
|
||||||
} else /* if (&channel == &stderrChannel) */ {
|
|
||||||
if (processChannelMode != QProcess::ForwardedChannels
|
|
||||||
&& processChannelMode != QProcess::ForwardedErrorChannel) {
|
|
||||||
if (!stderrChannel.reader) {
|
|
||||||
stderrChannel.reader = new QWindowsPipeReader(q);
|
|
||||||
q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
duplicateStdWriteChannel(channel.pipe, STD_ERROR_HANDLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (channel.reader) {
|
|
||||||
qt_create_pipe(channel.pipe, false);
|
if (!stdoutChannel.reader) {
|
||||||
channel.reader->setHandle(channel.pipe[0]);
|
stdoutChannel.reader = new QWindowsPipeReader(q);
|
||||||
channel.reader->startAsyncRead();
|
q->connect(stdoutChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput()));
|
||||||
|
}
|
||||||
|
} else /* if (&channel == &stderrChannel) */ {
|
||||||
|
if (processChannelMode == QProcess::ForwardedChannels
|
||||||
|
|| processChannelMode == QProcess::ForwardedErrorChannel) {
|
||||||
|
return duplicateStdWriteChannel(channel.pipe, STD_ERROR_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stderrChannel.reader) {
|
||||||
|
stderrChannel.reader = new QWindowsPipeReader(q);
|
||||||
|
q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!qt_create_pipe(channel.pipe, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
channel.reader->setHandle(channel.pipe[0]);
|
||||||
|
channel.reader->startAsyncRead();
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
case Channel::Redirect: {
|
case Channel::Redirect: {
|
||||||
// we're redirecting the channel to/from a file
|
// we're redirecting the channel to/from a file
|
||||||
SECURITY_ATTRIBUTES secAtt = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
|
SECURITY_ATTRIBUTES secAtt = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
|
||||||
@ -312,7 +314,9 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
Q_ASSERT(source == &stdoutChannel);
|
Q_ASSERT(source == &stdoutChannel);
|
||||||
Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
|
Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
|
||||||
|
|
||||||
qt_create_pipe(source->pipe, /* in = */ false); // source is stdout
|
if (!qt_create_pipe(source->pipe, /* in = */ false)) // source is stdout
|
||||||
|
return false;
|
||||||
|
|
||||||
sink->pipe[0] = source->pipe[0];
|
sink->pipe[0] = source->pipe[0];
|
||||||
source->pipe[0] = INVALID_Q_PIPE;
|
source->pipe[0] = INVALID_Q_PIPE;
|
||||||
|
|
||||||
@ -339,7 +343,9 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
Q_ASSERT(sink == &stdinChannel);
|
Q_ASSERT(sink == &stdinChannel);
|
||||||
Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
|
Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
|
||||||
|
|
||||||
qt_create_pipe(sink->pipe, /* in = */ true); // sink is stdin
|
if (!qt_create_pipe(sink->pipe, /* in = */ true)) // sink is stdin
|
||||||
|
return false;
|
||||||
|
|
||||||
source->pipe[1] = sink->pipe[1];
|
source->pipe[1] = sink->pipe[1];
|
||||||
sink->pipe[1] = INVALID_Q_PIPE;
|
sink->pipe[1] = INVALID_Q_PIPE;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user