QProcess: set the error message and state if qt_create_pipe() fails
It can only happen on resource exhaustion, which is an unlikely situation. That's probably why we didn't handle this case. But let's do it now. This necessitated that qt_create_pipe() return with errno/GetLastError() properly set, so save it and restore around functions that may change it (like qErrnoWarning()). Drive-by update of some warning messages. Testing this is not practical and is fragile, because it requires causing the resource exhaustion problem. Pick-to: 6.6 6.7 Change-Id: I76ffba14ece04f24b43efffd17aafe4f11f54c21 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
03f1ea3dcb
commit
b653e05c92
@ -423,7 +423,8 @@ static int qt_create_pipe(int *pipe)
|
|||||||
qt_safe_close(pipe[1]);
|
qt_safe_close(pipe[1]);
|
||||||
int pipe_ret = qt_safe_pipe(pipe);
|
int pipe_ret = qt_safe_pipe(pipe);
|
||||||
if (pipe_ret != 0) {
|
if (pipe_ret != 0) {
|
||||||
qErrnoWarning("QProcessPrivate::createPipe: Cannot create pipe %p", pipe);
|
QScopedValueRollback rollback(errno);
|
||||||
|
qErrnoWarning("QProcess: Cannot create pipe");
|
||||||
}
|
}
|
||||||
return pipe_ret;
|
return pipe_ret;
|
||||||
}
|
}
|
||||||
@ -472,8 +473,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
|
|
||||||
if (channel.type == Channel::Normal) {
|
if (channel.type == Channel::Normal) {
|
||||||
// we're piping this channel to our own process
|
// we're piping this channel to our own process
|
||||||
if (qt_create_pipe(channel.pipe) != 0)
|
if (qt_create_pipe(channel.pipe) != 0) {
|
||||||
|
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// create the socket notifiers
|
// create the socket notifiers
|
||||||
if (threadData.loadRelaxed()->hasEventDispatcher()) {
|
if (threadData.loadRelaxed()->hasEventDispatcher()) {
|
||||||
@ -552,8 +555,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
|
Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
|
||||||
|
|
||||||
Q_PIPE pipe[2] = { -1, -1 };
|
Q_PIPE pipe[2] = { -1, -1 };
|
||||||
if (qt_create_pipe(pipe) != 0)
|
if (qt_create_pipe(pipe) != 0) {
|
||||||
|
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
sink->pipe[0] = pipe[0];
|
sink->pipe[0] = pipe[0];
|
||||||
source->pipe[1] = pipe[1];
|
source->pipe[1] = pipe[1];
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
|
|||||||
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.");
|
||||||
|
SetLastError(dwError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,8 +155,10 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
|
|||||||
FILE_FLAG_OVERLAPPED,
|
FILE_FLAG_OVERLAPPED,
|
||||||
NULL);
|
NULL);
|
||||||
if (hClient == INVALID_HANDLE_VALUE) {
|
if (hClient == INVALID_HANDLE_VALUE) {
|
||||||
|
DWORD dwError = GetLastError();
|
||||||
qErrnoWarning("QProcess: CreateFile failed.");
|
qErrnoWarning("QProcess: CreateFile failed.");
|
||||||
CloseHandle(hServer);
|
CloseHandle(hServer);
|
||||||
|
SetLastError(dwError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,10 +175,12 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
|
|||||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
dwError = GetLastError();
|
||||||
qErrnoWarning(dwError, "QProcess: ConnectNamedPipe failed.");
|
qErrnoWarning(dwError, "QProcess: ConnectNamedPipe failed.");
|
||||||
CloseHandle(overlapped.hEvent);
|
CloseHandle(overlapped.hEvent);
|
||||||
CloseHandle(hClient);
|
CloseHandle(hClient);
|
||||||
CloseHandle(hServer);
|
CloseHandle(hServer);
|
||||||
|
SetLastError(dwError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,8 +206,13 @@ 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) {
|
||||||
return qt_create_pipe(channel.pipe, true, FALSE);
|
if (!qt_create_pipe(channel.pipe, true, FALSE)) {
|
||||||
|
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (&channel == &stdoutChannel) {
|
if (&channel == &stdoutChannel) {
|
||||||
if (!stdoutChannel.reader) {
|
if (!stdoutChannel.reader) {
|
||||||
@ -215,8 +225,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
|
|||||||
q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
|
q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!qt_create_pipe(channel.pipe, false, FALSE))
|
if (!qt_create_pipe(channel.pipe, false, FALSE)) {
|
||||||
|
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
channel.reader->setHandle(channel.pipe[0]);
|
channel.reader->setHandle(channel.pipe[0]);
|
||||||
channel.reader->startAsyncRead();
|
channel.reader->startAsyncRead();
|
||||||
@ -281,8 +293,10 @@ 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);
|
||||||
|
|
||||||
if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) // source is stdout
|
if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) { // source is stdout
|
||||||
|
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
|
||||||
return false;
|
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;
|
||||||
@ -301,8 +315,10 @@ 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);
|
||||||
|
|
||||||
if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) // sink is stdin
|
if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) { // sink is stdin
|
||||||
|
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
|
||||||
return false;
|
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