winrt: Fix potential crash when reading closed sockets
Using multiple concurrent requests can cause a delay between a socket closing and getting deleted. At that point the state was closingDown, but not wasDeleted yet. Especially on slower arm devices, callbacks are done from another thread causing synchronization issues. Hence closingDown needs to be synced and handleReadyRead needs to have more criterias to return early to avoid invalid access crashes. Easiest to reproduce is heavy scrolling on the mapviewer example when it downloads a huge amount of tiles and cancels those requests when not in view anymore. Change-Id: I442b6243bbefb3af938b6b1b3739a6a85b4887c0 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
parent
6e928460bc
commit
8714c99f65
@ -458,16 +458,21 @@ void QNativeSocketEngine::close()
|
||||
}
|
||||
|
||||
#if _MSC_VER >= 1900
|
||||
// To close the connection properly (not with a hard reset) all pending read operation have to
|
||||
// be finished or cancelled. The API isn't available on Windows 8.1 though.
|
||||
ComPtr<IStreamSocket3> socket3;
|
||||
hr = d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket3));
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
|
||||
HRESULT hr;
|
||||
// To close the connection properly (not with a hard reset) all pending read operation have to
|
||||
// be finished or cancelled. The API isn't available on Windows 8.1 though.
|
||||
ComPtr<IStreamSocket3> socket3;
|
||||
hr = d->tcpSocket()->QueryInterface(IID_PPV_ARGS(&socket3));
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
ComPtr<IAsyncAction> action;
|
||||
hr = socket3->CancelIOAsync(&action);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = QWinRTFunctions::await(action);
|
||||
ComPtr<IAsyncAction> action;
|
||||
hr = socket3->CancelIOAsync(&action);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = QWinRTFunctions::await(action);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
return S_OK;
|
||||
});
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
#endif // _MSC_VER >= 1900
|
||||
|
||||
@ -1261,9 +1266,12 @@ void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *actio
|
||||
|
||||
HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status)
|
||||
{
|
||||
Q_Q(QNativeSocketEngine);
|
||||
if (wasDeleted || isDeletingChildren)
|
||||
if (closingDown || wasDeleted || isDeletingChildren
|
||||
|| socketState == QAbstractSocket::UnconnectedState) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Q_Q(QNativeSocketEngine);
|
||||
|
||||
// A read in UnconnectedState will close the socket and return -1 and thus tell the caller,
|
||||
// that the connection was closed. The socket cannot be closed here, as the subsequent read
|
||||
|
@ -148,7 +148,7 @@ public:
|
||||
qintptr socketDescriptor;
|
||||
|
||||
bool notifyOnRead, notifyOnWrite, notifyOnException;
|
||||
bool closingDown;
|
||||
QAtomicInt closingDown;
|
||||
|
||||
enum ErrorString {
|
||||
NonBlockingInitFailedErrorString,
|
||||
|
Loading…
Reference in New Issue
Block a user