Q{LocalSocket|Process}/Win: handle write errors

To match the Unix behavior, we should emit errorOccurred() signal and
close the channel if the write operation fails.

Change-Id: Iac3acb18dbbfe6e7e8afb2555d9adaff1fe98d0f
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Alex Trotsenko 2021-09-11 17:32:09 +03:00
parent f4aaba593c
commit b2c3b3e8fe
7 changed files with 26 additions and 0 deletions

View File

@ -287,6 +287,7 @@ public:
#ifdef Q_OS_WIN
qint64 pipeWriterBytesToWrite() const;
void _q_bytesWritten(qint64 bytes);
void _q_writeFailed();
#else
bool _q_canWrite();
bool writeToStdin();

View File

@ -841,6 +841,8 @@ qint64 QProcess::writeData(const char *data, qint64 len)
d->stdinChannel.writer = new QWindowsPipeWriter(d->stdinChannel.pipe[1], this);
QObjectPrivate::connect(d->stdinChannel.writer, &QWindowsPipeWriter::bytesWritten,
d, &QProcessPrivate::_q_bytesWritten);
QObjectPrivate::connect(d->stdinChannel.writer, &QWindowsPipeWriter::writeFailed,
d, &QProcessPrivate::_q_writeFailed);
}
if (d->isWriteChunkCached(data, len))
@ -872,6 +874,12 @@ void QProcessPrivate::_q_bytesWritten(qint64 bytes)
closeWriteChannel();
}
void QProcessPrivate::_q_writeFailed()
{
closeWriteChannel();
setErrorAndEmit(QProcess::WriteError);
}
// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails
// with ERROR_ELEVATION_REQUIRED.
static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments,

View File

@ -341,6 +341,7 @@ bool QWindowsPipeWriter::consumePendingAndEmit(bool allowWinActPosting)
if (alive) {
writeBuffer.clear();
completionState = WriteDisabled;
emit writeFailed();
}
} else if (emitBytesWritten) {
emit bytesWritten(numberOfBytesWritten);

View File

@ -78,6 +78,7 @@ public:
Q_SIGNALS:
void bytesWritten(qint64 bytes);
void writeFailed();
protected:
bool event(QEvent *e) override;

View File

@ -137,6 +137,7 @@ public:
void _q_bytesWritten(qint64 bytes);
void _q_pipeClosed();
void _q_winError(ulong windowsError, const QString &function);
void _q_writeFailed();
HANDLE handle;
QWindowsPipeWriter *pipeWriter;
QWindowsPipeReader *pipeReader;

View File

@ -310,6 +310,8 @@ qint64 QLocalSocket::writeData(const char *data, qint64 len)
d->pipeWriter = new QWindowsPipeWriter(d->handle, this);
QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::bytesWritten,
d, &QLocalSocketPrivate::_q_bytesWritten);
QObjectPrivate::connect(d->pipeWriter, &QWindowsPipeWriter::writeFailed,
d, &QLocalSocketPrivate::_q_writeFailed);
}
if (d->isWriteChunkCached(data, len))
@ -455,6 +457,16 @@ void QLocalSocketPrivate::_q_bytesWritten(qint64 bytes)
q->disconnectFromServer();
}
void QLocalSocketPrivate::_q_writeFailed()
{
Q_Q(QLocalSocket);
error = QLocalSocket::PeerClosedError;
errorString = QLocalSocket::tr("Remote closed");
emit q->errorOccurred(error);
_q_pipeClosed();
}
qintptr QLocalSocket::socketDescriptor() const
{
Q_D(const QLocalSocket);

View File

@ -1531,6 +1531,7 @@ void tst_QLocalSocket::writeToDisconnected()
QVERIFY(server.listen("writeToDisconnected"));
QLocalSocket client;
QSignalSpy spyError(&client, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError)));
client.connectToServer("writeToDisconnected");
QVERIFY(client.waitForConnected(3000));
QVERIFY(server.waitForNewConnection(3000));
@ -1548,6 +1549,7 @@ void tst_QLocalSocket::writeToDisconnected()
QCOMPARE(client.bytesToWrite(), qint64(1));
QVERIFY(!client.waitForBytesWritten());
QCOMPARE(spyError.count(), 1);
QCOMPARE(client.state(), QLocalSocket::UnconnectedState);
}