let QWindowsPipeReader::stop() cancel the current I/O operation
In rare cases the I/O operation was still running after the destructor was running, which then modified free'd memory and caused a malformed heap. To prevent this, we ensure that QWindowsPipeReader::stop() cancels a running I/O operation and sets the readSequenceStarted flag correctly. Also, we prevent the start of a new read operation after we called stop(). Change-Id: If8a28bdf23a39a0e88c1770a6f66e2b24ea426bb Task-number: QTBUG-45601 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
This commit is contained in:
parent
a7f1c97d60
commit
5ce567c536
@ -44,6 +44,7 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
|
||||
handle(INVALID_HANDLE_VALUE),
|
||||
readBufferMaxSize(0),
|
||||
actualReadBufferSize(0),
|
||||
stopped(true),
|
||||
readSequenceStarted(false),
|
||||
pipeBroken(false),
|
||||
readyReadEmitted(false)
|
||||
@ -69,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped)
|
||||
|
||||
QWindowsPipeReader::~QWindowsPipeReader()
|
||||
{
|
||||
if (readSequenceStarted) {
|
||||
if (qt_cancelIo(handle, &overlapped))
|
||||
dataReadNotifier->waitForNotified(-1, &overlapped);
|
||||
else
|
||||
qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -87,6 +83,7 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
|
||||
handle = hPipeReadEnd;
|
||||
pipeBroken = false;
|
||||
readyReadEmitted = false;
|
||||
stopped = false;
|
||||
if (hPipeReadEnd != INVALID_HANDLE_VALUE) {
|
||||
dataReadNotifier->setHandle(hPipeReadEnd);
|
||||
dataReadNotifier->setEnabled(true);
|
||||
@ -95,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
|
||||
|
||||
/*!
|
||||
Stops the asynchronous read sequence.
|
||||
This function assumes that the file already has been closed.
|
||||
It does not cancel any I/O operation.
|
||||
If the read sequence is running then the I/O operation is canceled.
|
||||
*/
|
||||
void QWindowsPipeReader::stop()
|
||||
{
|
||||
dataReadNotifier->setEnabled(false);
|
||||
stopped = true;
|
||||
if (readSequenceStarted) {
|
||||
if (qt_cancelIo(handle, &overlapped)) {
|
||||
dataReadNotifier->waitForNotified(-1, &overlapped);
|
||||
} else {
|
||||
const DWORD dwError = GetLastError();
|
||||
if (dwError != ERROR_NOT_FOUND) {
|
||||
qErrnoWarning(dwError, "QWindowsPipeReader: qt_cancelIo on handle %x failed.",
|
||||
handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
readSequenceStarted = false;
|
||||
dataReadNotifier->setEnabled(false);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
@ -142,7 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
|
||||
}
|
||||
|
||||
if (!pipeBroken) {
|
||||
if (!readSequenceStarted)
|
||||
if (!readSequenceStarted && !stopped)
|
||||
startAsyncRead();
|
||||
if (readSoFar == 0)
|
||||
return -2; // signal EWOULDBLOCK
|
||||
@ -185,6 +193,13 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode,
|
||||
}
|
||||
|
||||
readSequenceStarted = false;
|
||||
|
||||
// After the reader was stopped, the only reason why this function can be called is the
|
||||
// completion of a cancellation. No signals should be emitted, and no new read sequence should
|
||||
// be started in this case.
|
||||
if (stopped)
|
||||
return;
|
||||
|
||||
if (pipeBroken) {
|
||||
emit pipeClosed();
|
||||
return;
|
||||
|
@ -97,6 +97,7 @@ private:
|
||||
qint64 readBufferMaxSize;
|
||||
QRingBuffer readBuffer;
|
||||
int actualReadBufferSize;
|
||||
bool stopped;
|
||||
bool readSequenceStarted;
|
||||
bool pipeBroken;
|
||||
bool readyReadEmitted;
|
||||
|
Loading…
Reference in New Issue
Block a user