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),
|
handle(INVALID_HANDLE_VALUE),
|
||||||
readBufferMaxSize(0),
|
readBufferMaxSize(0),
|
||||||
actualReadBufferSize(0),
|
actualReadBufferSize(0),
|
||||||
|
stopped(true),
|
||||||
readSequenceStarted(false),
|
readSequenceStarted(false),
|
||||||
pipeBroken(false),
|
pipeBroken(false),
|
||||||
readyReadEmitted(false)
|
readyReadEmitted(false)
|
||||||
@ -69,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped)
|
|||||||
|
|
||||||
QWindowsPipeReader::~QWindowsPipeReader()
|
QWindowsPipeReader::~QWindowsPipeReader()
|
||||||
{
|
{
|
||||||
if (readSequenceStarted) {
|
stop();
|
||||||
if (qt_cancelIo(handle, &overlapped))
|
|
||||||
dataReadNotifier->waitForNotified(-1, &overlapped);
|
|
||||||
else
|
|
||||||
qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -87,6 +83,7 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
|
|||||||
handle = hPipeReadEnd;
|
handle = hPipeReadEnd;
|
||||||
pipeBroken = false;
|
pipeBroken = false;
|
||||||
readyReadEmitted = false;
|
readyReadEmitted = false;
|
||||||
|
stopped = false;
|
||||||
if (hPipeReadEnd != INVALID_HANDLE_VALUE) {
|
if (hPipeReadEnd != INVALID_HANDLE_VALUE) {
|
||||||
dataReadNotifier->setHandle(hPipeReadEnd);
|
dataReadNotifier->setHandle(hPipeReadEnd);
|
||||||
dataReadNotifier->setEnabled(true);
|
dataReadNotifier->setEnabled(true);
|
||||||
@ -95,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd)
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Stops the asynchronous read sequence.
|
Stops the asynchronous read sequence.
|
||||||
This function assumes that the file already has been closed.
|
If the read sequence is running then the I/O operation is canceled.
|
||||||
It does not cancel any I/O operation.
|
|
||||||
*/
|
*/
|
||||||
void QWindowsPipeReader::stop()
|
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;
|
readSequenceStarted = false;
|
||||||
|
dataReadNotifier->setEnabled(false);
|
||||||
handle = INVALID_HANDLE_VALUE;
|
handle = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!pipeBroken) {
|
if (!pipeBroken) {
|
||||||
if (!readSequenceStarted)
|
if (!readSequenceStarted && !stopped)
|
||||||
startAsyncRead();
|
startAsyncRead();
|
||||||
if (readSoFar == 0)
|
if (readSoFar == 0)
|
||||||
return -2; // signal EWOULDBLOCK
|
return -2; // signal EWOULDBLOCK
|
||||||
@ -185,6 +193,13 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
readSequenceStarted = false;
|
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) {
|
if (pipeBroken) {
|
||||||
emit pipeClosed();
|
emit pipeClosed();
|
||||||
return;
|
return;
|
||||||
|
@ -97,6 +97,7 @@ private:
|
|||||||
qint64 readBufferMaxSize;
|
qint64 readBufferMaxSize;
|
||||||
QRingBuffer readBuffer;
|
QRingBuffer readBuffer;
|
||||||
int actualReadBufferSize;
|
int actualReadBufferSize;
|
||||||
|
bool stopped;
|
||||||
bool readSequenceStarted;
|
bool readSequenceStarted;
|
||||||
bool pipeBroken;
|
bool pipeBroken;
|
||||||
bool readyReadEmitted;
|
bool readyReadEmitted;
|
||||||
|
Loading…
Reference in New Issue
Block a user