From a4d26cf522b966056e47e47a004b7e4d668e3a2d Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Fri, 8 Apr 2016 16:55:39 +0300 Subject: QWindowsPipeWriter: ensure validity of the write buffer QWindowsPipeWriter uses asynchronous API to perform writing. Once a cycle has been started, the write buffer must remain valid until the write operation is completed. To avoid data corruption and possibly undefined behavior, this patch makes QWindowsPipeWriter::write() take a QByteArray, which it keeps alive for the duration of the write cycle. Autotest-by: Thomas Hartmann Task-number: QTBUG-52401 Change-Id: Ia35faee735c4e684267daa1f6bd689512b670cd2 Reviewed-by: Joerg Bornemann --- .../socket/qlocalsocket/tst_qlocalsocket.cpp | 108 +++++++++++++++++++++ 1 file changed, 108 insertions(+) (limited to 'tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp') diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index 99f40ca215..6e55b15a18 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -78,6 +79,9 @@ private slots: void readBufferOverflow(); + void simpleCommandProtocol1(); + void simpleCommandProtocol2(); + void fullPath(); void hitMaximumConnections_data(); @@ -630,6 +634,110 @@ void tst_QLocalSocket::readBufferOverflow() QCOMPARE(client.bytesAvailable(), 0); } +static qint64 writeCommand(const QVariant &command, QIODevice *device, int commandCounter) +{ + QByteArray block; + QDataStream out(&block, QIODevice::WriteOnly); + out << qint64(0); + out << commandCounter; + out << command; + out.device()->seek(0); + out << qint64(block.size() - sizeof(qint64)); + return device->write(block); +} + +static QVariant readCommand(QIODevice *ioDevice, int *readCommandCounter, bool readSize = true) +{ + QDataStream in(ioDevice); + qint64 blockSize; + int commandCounter; + if (readSize) + in >> blockSize; + in >> commandCounter; + *readCommandCounter = commandCounter; + + QVariant command; + in >> command; + + return command; +} + +void tst_QLocalSocket::simpleCommandProtocol1() +{ + QLocalServer server; + server.listen(QStringLiteral("simpleProtocol")); + + QLocalSocket localSocketWrite; + localSocketWrite.connectToServer(server.serverName()); + QVERIFY(server.waitForNewConnection()); + QLocalSocket *localSocketRead = server.nextPendingConnection(); + QVERIFY(localSocketRead); + + int readCounter = 0; + for (int i = 0; i < 2000; ++i) { + const QVariant command(QRect(readCounter, i, 10, 10)); + const qint64 blockSize = writeCommand(command, &localSocketWrite, i); + while (localSocketWrite.bytesToWrite()) + QVERIFY(localSocketWrite.waitForBytesWritten()); + while (localSocketRead->bytesAvailable() < blockSize) { + QVERIFY(localSocketRead->waitForReadyRead(1000)); + } + const QVariant variant = readCommand(localSocketRead, &readCounter); + QCOMPARE(readCounter, i); + QCOMPARE(variant, command); + } +} + +void tst_QLocalSocket::simpleCommandProtocol2() +{ + QLocalServer server; + server.listen(QStringLiteral("simpleProtocol")); + + QLocalSocket localSocketWrite; + localSocketWrite.connectToServer(server.serverName()); + QVERIFY(server.waitForNewConnection()); + QLocalSocket* localSocketRead = server.nextPendingConnection(); + QVERIFY(localSocketRead); + + int readCounter = 0; + qint64 writtenBlockSize = 0; + qint64 blockSize = 0; + + QObject::connect(localSocketRead, &QLocalSocket::readyRead, [&] { + forever { + if (localSocketRead->bytesAvailable() < sizeof(qint64)) + return; + + if (blockSize == 0) { + QDataStream in(localSocketRead); + in >> blockSize; + } + + if (localSocketRead->bytesAvailable() < blockSize) + return; + + int commandNumber = 0; + const QVariant variant = readCommand(localSocketRead, &commandNumber, false); + QCOMPARE(writtenBlockSize, blockSize); + QCOMPARE(readCounter, commandNumber); + QCOMPARE(variant.userType(), (int)QMetaType::QRect); + + readCounter++; + blockSize = 0; + } + }); + + for (int i = 0; i < 500; ++i) { + const QVariant command(QRect(readCounter, i, 10, 10)); + writtenBlockSize = writeCommand(command, &localSocketWrite, i) - sizeof(qint64); + if (i % 10 == 0) + QTest::qWait(1); + } + + localSocketWrite.abort(); + QVERIFY(localSocketRead->waitForDisconnected(1000)); +} + // QLocalSocket/Server can take a name or path, check that it works as expected void tst_QLocalSocket::fullPath() { -- cgit v1.2.3