From f58e882b7594c59b6050d3c87562fcf836d10f60 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 14 Apr 2015 10:58:26 +0200 Subject: [PATCH 01/23] QLockFile: fix deadlock when the lock file is corrupted [ChangeLog][QtCore][QLockFile] Fixed a deadlock when the lock file is corrupted. Task-number: QTBUG-44771 Change-Id: Ic490b09d70ff1cc1733b64949889a73720b2d0f3 Reviewed-by: David Faure --- src/corelib/io/qlockfile_unix.cpp | 10 ++++----- src/corelib/io/qlockfile_win.cpp | 22 +++++++++---------- .../corelib/io/qlockfile/tst_qlockfile.cpp | 17 ++++++++++++++ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index bf1015a7be7..dc9f8f73c4c 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -181,11 +181,11 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; - if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { - if (::kill(pid, 0) == -1 && errno == ESRCH) - return true; // PID doesn't exist anymore + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { + if (::kill(pid, 0) == -1 && errno == ESRCH) + return true; // PID doesn't exist anymore + } } const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); return staleLockTime > 0 && age > staleLockTime; diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index f9f29090d76..3587c7bffe2 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -115,21 +115,21 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; // On WinRT there seems to be no way of obtaining information about other // processes due to sandboxing #ifndef Q_OS_WINRT - if (hostname == QString::fromLocal8Bit(localHostName())) { - HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); - if (!procHandle) - return true; - // We got a handle but check if process is still alive - DWORD dwR = ::WaitForSingleObject(procHandle, 0); - ::CloseHandle(procHandle); - if (dwR == WAIT_TIMEOUT) - return true; + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname == QString::fromLocal8Bit(localHostName())) { + HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!procHandle) + return true; + // We got a handle but check if process is still alive + DWORD dwR = ::WaitForSingleObject(procHandle, 0); + ::CloseHandle(procHandle); + if (dwR == WAIT_TIMEOUT) + return true; + } } #endif // !Q_OS_WINRT const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index 77bef94550f..12bea6769c6 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -58,6 +58,7 @@ private slots: void staleLongLockFromBusyProcess(); void staleLockRace(); void noPermissions(); + void corruptedLockFile(); public: QString m_helperApp; @@ -415,5 +416,21 @@ void tst_QLockFile::noPermissions() QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError)); } +void tst_QLockFile::corruptedLockFile() +{ + const QString fileName = dir.path() + "/corruptedLockFile"; + + { + // Create a empty file. Typically the result of a computer crash or hard disk full. + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly)); + } + + QLockFile secondLock(fileName); + secondLock.setStaleLockTime(100); + QVERIFY(secondLock.tryLock(10000)); + QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); +} + QTEST_MAIN(tst_QLockFile) #include "tst_qlockfile.moc" From 0c28e1ab7a430d56702cb8545320356de3bda711 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 14 Jan 2015 19:27:22 +0300 Subject: [PATCH 02/23] Fix finding the closest active touch point for the pressed touch point Currently pressed touch point is added to the list of active touch points in Gui module. It must be excluded from consideration when we traverse the list. Task-number: QTBUG-43255 Change-Id: Idddab093b1f6a79122cf18fad7f43bfc93ce7eea Reviewed-by: Shawn Rutledge Reviewed-by: Marc Mutz --- src/widgets/kernel/qapplication.cpp | 7 +-- src/widgets/kernel/qapplication_p.h | 2 +- .../widgets/kernel/qwidget/tst_qwidget.cpp | 53 +++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index abd0231b001..ba14a06af4f 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -4275,15 +4275,16 @@ void QApplicationPrivate::cleanupMultitouch_sys() { } -QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos) +QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint) { + const QPointF screenPos = touchPoint.screenPos(); int closestTouchPointId = -1; QObject *closestTarget = 0; qreal closestDistance = qreal(0.); QHash::const_iterator it = activeTouchPoints.constBegin(), ite = activeTouchPoints.constEnd(); while (it != ite) { - if (it.key().device == device) { + if (it.key().device == device && it.key().touchPointId != touchPoint.id()) { const QTouchEvent::TouchPoint &touchPoint = it->touchPoint; qreal dx = screenPos.x() - touchPoint.screenPos().x(); qreal dy = screenPos.y() - touchPoint.screenPos().y(); @@ -4339,7 +4340,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, } if (device->type() == QTouchDevice::TouchScreen) { - QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint.screenPos()); + QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint); QWidget *widget = static_cast(target.data()); if (closestWidget && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 7d97235c66b..7f76d1ba979 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -280,7 +280,7 @@ public: void initializeMultitouch_sys(); void cleanupMultitouch(); void cleanupMultitouch_sys(); - QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos); + QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); static bool translateRawTouchEvent(QWidget *widget, diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index ae6d62c3321..717039d64e8 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -435,6 +435,7 @@ private slots: void grabKeyboard(); void touchEventSynthesizedMouseEvent(); + void touchUpdateOnNewTouch(); void styleSheetPropagation(); @@ -9763,6 +9764,9 @@ class TouchMouseWidget : public QWidget { public: explicit TouchMouseWidget(QWidget *parent = 0) : QWidget(parent), + m_touchBeginCount(0), + m_touchUpdateCount(0), + m_touchEndCount(0), m_touchEventCount(0), m_acceptTouch(false), m_mouseEventCount(0), @@ -9789,6 +9793,12 @@ protected: case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: + if (e->type() == QEvent::TouchBegin) + ++m_touchBeginCount; + else if (e->type() == QEvent::TouchUpdate) + ++m_touchUpdateCount; + else if (e->type() == QEvent::TouchEnd) + ++m_touchEndCount; ++m_touchEventCount; if (m_acceptTouch) e->accept(); @@ -9813,6 +9823,9 @@ protected: } public: + int m_touchBeginCount; + int m_touchUpdateCount; + int m_touchEndCount; int m_touchEventCount; bool m_acceptTouch; int m_mouseEventCount; @@ -9933,6 +9946,46 @@ void tst_QWidget::touchEventSynthesizedMouseEvent() } } +void tst_QWidget::touchUpdateOnNewTouch() +{ + QTouchDevice *device = new QTouchDevice; + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device); + + TouchMouseWidget widget; + widget.setAcceptTouch(true); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(new QWidget); + widget.setLayout(layout); + widget.show(); + + QWindow* window = widget.windowHandle(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QCOMPARE(widget.m_touchBeginCount, 0); + QCOMPARE(widget.m_touchUpdateCount, 0); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).press(0, QPoint(20, 20), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 0); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).move(0, QPoint(25, 25), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 1); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).stationary(0).press(1, QPoint(40, 40), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 2); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).stationary(1).release(0, QPoint(25, 25), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 3); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).release(1, QPoint(40, 40), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 3); + QCOMPARE(widget.m_touchEndCount, 1); +} + void tst_QWidget::styleSheetPropagation() { QTableView tw; From 6cea45cc24ff1e29ded753656b2830f0fae06742 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 15 Apr 2015 14:34:35 +0200 Subject: [PATCH 03/23] Doc: fix description of QWindowsPipeReader::read Change-Id: Ib34fc77cc05125cf698e255a5d80dbf83cf4575e Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipereader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index e932fc0c02a..c3159ca3671 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -119,7 +119,7 @@ qint64 QWindowsPipeReader::bytesAvailable() const } /*! - Stops the asynchronous read sequence. + Copies at most \c{maxlen} bytes from the internal read buffer to \c{data}. */ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) { From 5fc52ba6e2a5425ea8edcef8aad80d9d20f47f9c Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 16 Apr 2015 14:13:44 +0200 Subject: [PATCH 04/23] QWindowsPipeReader: zero OVERLAPPED struct before every ReadFile According to the documentation we should always pass a zeroed OVERLAPPED object to ReadFile. Change-Id: I3f822af46a2c38e029e02461f706c4fd91c00c50 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipereader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index c3159ca3671..8b1ec838335 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -89,7 +89,6 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) readBuffer.clear(); actualReadBufferSize = 0; handle = hPipeReadEnd; - ZeroMemory(&overlapped, sizeof(overlapped)); pipeBroken = false; readyReadEmitted = false; if (hPipeReadEnd != INVALID_HANDLE_VALUE) { @@ -206,6 +205,7 @@ void QWindowsPipeReader::startAsyncRead() char *ptr = readBuffer.reserve(bytesToRead); readSequenceStarted = true; + ZeroMemory(&overlapped, sizeof(overlapped)); if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { // We get notified by the QWinOverlappedIoNotifier - even in the synchronous case. return; From bb8f62148052e1208b4fe00a3fc6f25fa74432ac Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 16 Apr 2015 13:46:45 +0200 Subject: [PATCH 05/23] remove emitReadyReadTimer from QWindowsPipeReader The zero timeout singleshot timer emitReadyReadTimer was used to emit the readyRead signal via the event loop in case of a synchronous read. In that particular case, ReadFile would return successfully, and the notified slot would not be called. Now, that we use an I/O completion port, the notified slot is always called, even in the synchronous case. The emitReadyReadTimer is not needed anymore. This is also supported by the fact that the timer is immediately stopped in notified() after it was started in completeAsyncRead(). Change-Id: I93bcde5f067bf89a1d49005a3fddda4c8c8c95fc Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipereader.cpp | 9 --------- src/corelib/io/qwindowspipereader_p.h | 2 -- 2 files changed, 11 deletions(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 8b1ec838335..64f21d5a92c 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -36,7 +36,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -46,12 +45,9 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) readBufferMaxSize(0), actualReadBufferSize(0), readSequenceStarted(false), - emitReadyReadTimer(new QTimer(this)), pipeBroken(false), readyReadEmitted(false) { - emitReadyReadTimer->setSingleShot(true); - connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead())); dataReadNotifier = new QWinOverlappedIoNotifier(this); connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified); } @@ -146,8 +142,6 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) } if (!pipeBroken) { - if (!actualReadBufferSize) - emitReadyReadTimer->stop(); if (!readSequenceStarted) startAsyncRead(); if (readSoFar == 0) @@ -177,7 +171,6 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode, return; } startAsyncRead(); - emitReadyReadTimer->stop(); readyReadEmitted = true; emit readyRead(); } @@ -266,8 +259,6 @@ bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode) actualReadBufferSize += bytesRead; readBuffer.truncate(actualReadBufferSize); - if (!emitReadyReadTimer->isActive()) - emitReadyReadTimer->start(); return true; } diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index ecc6974efa7..6eead60fd5c 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -47,7 +47,6 @@ #include #include -#include #include #include @@ -100,7 +99,6 @@ private: QRingBuffer readBuffer; int actualReadBufferSize; bool readSequenceStarted; - QTimer *emitReadyReadTimer; bool pipeBroken; bool readyReadEmitted; }; From a7f1c97d6096b7f9cc44df275b20d91cc75f7347 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 16 Apr 2015 16:18:45 +0200 Subject: [PATCH 06/23] inline QWindowsPipeReader::completeAsyncRead There's exactly one caller for this private method, and future code will be a bit simpler after moving the code to the calling site. Change-Id: Ibc65f91c770f9f29b317ceddb39a67d52106da33 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qwindowspipereader.cpp | 54 ++++++++++++--------------- src/corelib/io/qwindowspipereader_p.h | 1 - 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 64f21d5a92c..cc407dbed99 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -165,11 +165,33 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode, { if (&overlapped != notifiedOverlapped) return; - if (!completeAsyncRead(numberOfBytesRead, errorCode)) { + + switch (errorCode) { + case ERROR_SUCCESS: + break; + case ERROR_MORE_DATA: + // This is not an error. We're connected to a message mode + // pipe and the message didn't fit into the pipe's system + // buffer. We will read the remaining data in the next call. + break; + case ERROR_BROKEN_PIPE: + case ERROR_PIPE_NOT_CONNECTED: pipeBroken = true; + break; + default: + emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); + pipeBroken = true; + break; + } + + readSequenceStarted = false; + if (pipeBroken) { emit pipeClosed(); return; } + + actualReadBufferSize += numberOfBytesRead; + readBuffer.truncate(actualReadBufferSize); startAsyncRead(); readyReadEmitted = true; emit readyRead(); @@ -232,36 +254,6 @@ void QWindowsPipeReader::startAsyncRead() } } -/*! - \internal - Sets the correct size of the read buffer after a read operation. - Returns \c false, if an error occurred or the connection dropped. - */ -bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode) -{ - readSequenceStarted = false; - - switch (errorCode) { - case ERROR_SUCCESS: - break; - case ERROR_MORE_DATA: - // This is not an error. We're connected to a message mode - // pipe and the message didn't fit into the pipe's system - // buffer. We will read the remaining data in the next call. - break; - case ERROR_BROKEN_PIPE: - case ERROR_PIPE_NOT_CONNECTED: - return false; - default: - emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); - return false; - } - - actualReadBufferSize += bytesRead; - readBuffer.truncate(actualReadBufferSize); - return true; -} - /*! \internal Returns the number of available bytes in the pipe. diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index 6eead60fd5c..7651093b054 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -88,7 +88,6 @@ private Q_SLOTS: void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped); private: - bool completeAsyncRead(DWORD bytesRead, DWORD errorCode); DWORD checkPipeState(); private: From 5ce567c536fde6b7cb93657d14df404f3e270119 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 15 Apr 2015 15:37:24 +0200 Subject: [PATCH 07/23] 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 --- src/corelib/io/qwindowspipereader.cpp | 35 +++++++++++++++++++-------- src/corelib/io/qwindowspipereader_p.h | 1 + 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index cc407dbed99..4ed9674f365 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -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; diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index 7651093b054..b0a23e1a511 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -97,6 +97,7 @@ private: qint64 readBufferMaxSize; QRingBuffer readBuffer; int actualReadBufferSize; + bool stopped; bool readSequenceStarted; bool pipeBroken; bool readyReadEmitted; From 50ce5a68301dee2fd00b7c6ccc615257a2353098 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 30 Mar 2015 14:07:22 +0200 Subject: [PATCH 08/23] Cocoa: Handle the event passed into the global monitor correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the global monitor was used it did not get the right position for the mouse event and as a result it caused context menus to appear and disappear instantly when right clicking over a non active window. This ensures that the events are sent correctly with the right position and button information. Task-number: QTBUG-45015 Change-Id: I9b17a725e656c716c4e22117b4513e64c357b266 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 2adea0f4937..0f9c2c1c86a 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -680,8 +680,10 @@ void QCocoaWindow::setVisible(bool visible) && [m_nsWindow isKindOfClass:[NSPanel class]]) { [(NSPanel *)m_nsWindow setWorksWhenModal:YES]; if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) { - monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDown handler:^(NSEvent *) { - QWindowSystemInterface::handleMouseEvent(window(), QPointF(-1, -1), QPointF(window()->framePosition() - QPointF(1, 1)), Qt::LeftButton); + monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) { + QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]); + QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint, + cocoaButton2QtButton([e buttonNumber])); }]; } } From cff39fba10ffc10ee4dcfdc66ff6528eb26462d3 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Fri, 10 Apr 2015 14:09:53 +0200 Subject: [PATCH 09/23] QNAM: Fix upload corruptions when server closes connection This patch fixes several upload corruptions if the server closes the connection while/before we send data into it. They happen inside multiple places in the HTTP layer and are explained in the comments. Corruptions are: * The upload byte device has an in-flight signal with pending upload data, if it gets reset (because server closes the connection) then the re-send of the request was sometimes taking this stale in-flight pending upload data. * Because some signals were DirectConnection and some were QueuedConnection, there was a chance that a direct signal overtakes a queued signal. The state machine then sent data down the socket which was buffered there (and sent later) although it did not match the current state of the state machine when it was actually sent. * A socket was seen as being able to have requests sent even though it was not encrypted yet. This relates to the previous corruption where data is stored inside the socket's buffer and then sent later. The included auto test produces all fixed corruptions, I detected no regressions via the other tests. This code also adds a bit of sanity checking to protect from possible further problems. [ChangeLog][QtNetwork] Fix HTTP(s) upload corruption when server closes connection Change-Id: I54c883925ec897050941498f139c4b523030432e Reviewed-by: Peter Hartmann --- src/corelib/io/qnoncontiguousbytedevice.cpp | 18 ++ src/corelib/io/qnoncontiguousbytedevice_p.h | 4 + .../access/qhttpnetworkconnectionchannel.cpp | 35 +++- .../access/qhttpnetworkconnectionchannel_p.h | 2 + src/network/access/qhttpprotocolhandler.cpp | 7 + src/network/access/qhttpthreaddelegate_p.h | 36 +++- src/network/access/qnetworkreplyhttpimpl.cpp | 25 ++- src/network/access/qnetworkreplyhttpimpl_p.h | 7 +- .../qnetworkreply/tst_qnetworkreply.cpp | 175 +++++++++++++++++- 9 files changed, 279 insertions(+), 30 deletions(-) diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index 11510a83972..760ca3d933a 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -236,6 +236,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size() return byteArray->size(); } +qint64 QNonContiguousByteDeviceByteArrayImpl::pos() +{ + return currentPosition; +} + QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer rb) : QNonContiguousByteDevice(), currentPosition(0) { @@ -273,6 +278,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd() return currentPosition >= size(); } +qint64 QNonContiguousByteDeviceRingBufferImpl::pos() +{ + return currentPosition; +} + bool QNonContiguousByteDeviceRingBufferImpl::reset() { if (resetDisabled) @@ -406,6 +416,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size() return device->size() - initialPosition; } +qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() +{ + if (device->isSequential()) + return -1; + + return device->pos(); +} + QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) { byteDevice = bd; diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index c05ae11b0f4..4d7b7b043e2 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -61,6 +61,7 @@ public: virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; virtual bool advanceReadPointer(qint64 amount) = 0; virtual bool atEnd() = 0; + virtual qint64 pos() { return -1; } virtual bool reset() = 0; void disableReset(); bool isResetDisabled() { return resetDisabled; } @@ -106,6 +107,7 @@ public: bool atEnd(); bool reset(); qint64 size(); + qint64 pos() Q_DECL_OVERRIDE; protected: QByteArray* byteArray; qint64 currentPosition; @@ -121,6 +123,7 @@ public: bool atEnd(); bool reset(); qint64 size(); + qint64 pos() Q_DECL_OVERRIDE; protected: QSharedPointer ringBuffer; qint64 currentPosition; @@ -138,6 +141,7 @@ public: bool atEnd(); bool reset(); qint64 size(); + qint64 pos() Q_DECL_OVERRIDE; protected: QIODevice* device; QByteArray* currentReadBuffer; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 9f63280bf8d..49c6793b1f6 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init() socket->setProxy(QNetworkProxy::NoProxy); #endif + // We want all signals (except the interactive ones) be connected as QueuedConnection + // because else we're falling into cases where we recurse back into the socket code + // and mess up the state. Always going to the event loop (and expecting that when reading/writing) + // is safer. QObject::connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(socket, SIGNAL(connected()), this, SLOT(_q_connected()), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(_q_readyRead()), - Qt::DirectConnection); + Qt::QueuedConnection); // The disconnected() and error() signals may already come // while calling connectToHost(). @@ -143,13 +147,13 @@ void QHttpNetworkConnectionChannel::init() // won't be a sslSocket if encrypt is false QObject::connect(sslSocket, SIGNAL(encrypted()), this, SLOT(_q_encrypted()), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(sslSocket, SIGNAL(sslErrors(QList)), this, SLOT(_q_sslErrors(QList)), Qt::DirectConnection); QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); if (ignoreAllSslErrors) sslSocket->ignoreSslErrors(); @@ -186,8 +190,11 @@ void QHttpNetworkConnectionChannel::close() // pendingEncrypt must only be true in between connected and encrypted states pendingEncrypt = false; - if (socket) + if (socket) { + // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while + // there is no socket yet. socket->close(); + } } @@ -353,6 +360,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection() } return false; } + + // This code path for ConnectedState + if (pendingEncrypt) { + // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up + // and corrupt the things sent to the server. + return false; + } + return true; } @@ -659,6 +674,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes) { Q_UNUSED(bytes); + if (ssl) { + // In the SSL case we want to send data from encryptedBytesWritten signal since that one + // is the one going down to the actual network, not only into some SSL buffer. + return; + } + // bytes have been written to the socket. write even more of them :) if (isSocketWriting()) sendRequest(); @@ -734,7 +755,7 @@ void QHttpNetworkConnectionChannel::_q_connected() // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again! //channels[i].reconnectAttempts = 2; - if (pendingEncrypt) { + if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState #ifndef QT_NO_SSL if (connection->sslContext().isNull()) { // this socket is making the 1st handshake for this connection, diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 692c0e6a946..231fe111358 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -83,6 +83,8 @@ typedef QPair HttpMessagePair; class QHttpNetworkConnectionChannel : public QObject { Q_OBJECT public: + // TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt). + // Also add an Unconnected state so IdleState does not have double meaning. enum ChannelState { IdleState = 0, // ready to send request ConnectingState = 1, // connecting to host diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index 28e10f751e6..33579485192 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest() // nothing to read currently, break the loop break; } else { + if (m_channel->written != uploadByteDevice->pos()) { + // Sanity check. This was useful in tracking down an upload corruption. + qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos(); + Q_ASSERT(m_channel->written == uploadByteDevice->pos()); + m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure); + return false; + } qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize); if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { // socket broke down diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 16610828cba..b5534093913 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -187,6 +187,7 @@ protected: QByteArray m_dataArray; bool m_atEnd; qint64 m_size; + qint64 m_pos; // to match calls of haveDataSlot with the expected position public: QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s) : QNonContiguousByteDevice(), @@ -194,7 +195,8 @@ public: m_amount(0), m_data(0), m_atEnd(aE), - m_size(s) + m_size(s), + m_pos(0) { } @@ -202,6 +204,11 @@ public: { } + qint64 pos() Q_DECL_OVERRIDE + { + return m_pos; + } + const char* readPointer(qint64 maximumLength, qint64 &len) { if (m_amount > 0) { @@ -229,11 +236,10 @@ public: m_amount -= a; m_data += a; + m_pos += a; - // To main thread to inform about our state - emit processedData(a); - - // FIXME possible optimization, already ask user thread for some data + // To main thread to inform about our state. The m_pos will be sent as a sanity check. + emit processedData(m_pos, a); return true; } @@ -250,10 +256,21 @@ public: { m_amount = 0; m_data = 0; + m_dataArray.clear(); + + if (wantDataPending) { + // had requested the user thread to send some data (only 1 in-flight at any moment) + wantDataPending = false; + } // Communicate as BlockingQueuedConnection bool b = false; emit resetData(&b); + if (b) { + // the reset succeeded, we're at pos 0 again + m_pos = 0; + // the HTTP code will anyway abort the request if !b. + } return b; } @@ -264,8 +281,13 @@ public: public slots: // From user thread: - void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize) + void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize) { + if (pos != m_pos) { + // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the + // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk. + return; + } wantDataPending = false; m_dataArray = dataArray; @@ -285,7 +307,7 @@ signals: // to main thread: void wantData(qint64); - void processedData(qint64); + void processedData(qint64 pos, qint64 amount); void resetData(bool *b); }; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 4ce7303dbbf..974a101e9cd 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() , synchronous(false) , state(Idle) , statusCode(0) + , uploadByteDevicePosition(false) , uploadDeviceChoking(false) , outgoingData(0) , bytesUploaded(-1) @@ -863,9 +864,9 @@ void QNetworkReplyHttpImplPrivate::postRequest() q, SLOT(uploadByteDeviceReadyReadSlot()), Qt::QueuedConnection); - // From main thread to user thread: - QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)), - forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection); + // From user thread to http thread: + QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)), + forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection); QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), forwardUploadDevice, SIGNAL(readyRead()), Qt::QueuedConnection); @@ -873,8 +874,8 @@ void QNetworkReplyHttpImplPrivate::postRequest() // From http thread to user thread: QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)), q, SLOT(wantUploadDataSlot(qint64))); - QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)), - q, SLOT(sentUploadDataSlot(qint64))); + QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)), + q, SLOT(sentUploadDataSlot(qint64,qint64))); QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)), q, SLOT(resetUploadDataSlot(bool*)), Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued! @@ -1268,12 +1269,22 @@ void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfig void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r) { *r = uploadByteDevice->reset(); + if (*r) { + // reset our own position which is used for the inter-thread communication + uploadByteDevicePosition = 0; + } } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread -void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount) +void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount) { + if (uploadByteDevicePosition + amount != pos) { + // Sanity check, should not happen. + error(QNetworkReply::UnknownNetworkError, ""); + return; + } uploadByteDevice->advanceReadPointer(amount); + uploadByteDevicePosition += amount; } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread @@ -1298,7 +1309,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize) QByteArray dataArray(data, currentUploadDataLength); // Communicate back to HTTP thread - emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); + emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); } void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot() diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 77d9c5a368a..1940922f6e9 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -120,7 +120,7 @@ public: Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r)) Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64)) - Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64)) + Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64)) Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot()) Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64)) Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose()) @@ -144,7 +144,7 @@ signals: void startHttpRequestSynchronously(); - void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize); + void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize); }; class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate @@ -195,6 +195,7 @@ public: // upload QNonContiguousByteDevice* createUploadByteDevice(); QSharedPointer uploadByteDevice; + qint64 uploadByteDevicePosition; bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment QIODevice *outgoingData; QSharedPointer outgoingDataBuffer; @@ -283,7 +284,7 @@ public: // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread: void resetUploadDataSlot(bool *r); void wantUploadDataSlot(qint64); - void sentUploadDataSlot(qint64); + void sentUploadDataSlot(qint64, qint64); // From user's QNonContiguousByteDevice void uploadByteDeviceReadyReadSlot(); diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 3ccedf62488..d2edf67a82c 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -457,6 +457,10 @@ private Q_SLOTS: void putWithRateLimiting(); +#ifndef QT_NO_SSL + void putWithServerClosingConnectionImmediately(); +#endif + // NOTE: This test must be last! void parentingRepliesToTheApp(); private: @@ -4718,18 +4722,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag() class SslServer : public QTcpServer { Q_OBJECT public: - SslServer() : socket(0) {}; + SslServer() : socket(0), m_ssl(true) {} void incomingConnection(qintptr socketDescriptor) { QSslSocket *serverSocket = new QSslSocket; serverSocket->setParent(this); if (serverSocket->setSocketDescriptor(socketDescriptor)) { + connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + if (!m_ssl) { + emit newPlainConnection(serverSocket); + return; + } QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath(); if (testDataDir.isEmpty()) testDataDir = QCoreApplication::applicationDirPath(); connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot())); - connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); serverSocket->setProtocol(QSsl::AnyProtocol); connect(serverSocket, SIGNAL(sslErrors(QList)), serverSocket, SLOT(ignoreSslErrors())); serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem"); @@ -4740,11 +4748,12 @@ public: } } signals: - void newEncryptedConnection(); + void newEncryptedConnection(QSslSocket *s); + void newPlainConnection(QSslSocket *s); public slots: void encryptedSlot() { socket = (QSslSocket*) sender(); - emit newEncryptedConnection(); + emit newEncryptedConnection(socket); } void readyReadSlot() { // for the incoming sockets, not the server socket @@ -4753,6 +4762,7 @@ public slots: public: QSslSocket *socket; + bool m_ssl; }; // very similar to ioPostToHttpUploadProgress but for SSL @@ -4780,7 +4790,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QNetworkReplyPtr reply(manager.post(request, sourceFile)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); - connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop())); connect(reply, SIGNAL(sslErrors(QList)), reply.data(), SLOT(ignoreSslErrors())); // get the request started and the incoming socket connected @@ -4788,7 +4798,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QVERIFY(!QTestEventLoop::instance().timeout()); QTcpSocket *incomingSocket = server.socket; QVERIFY(incomingSocket); - disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop())); incomingSocket->setReadBufferSize(1*1024); @@ -7905,6 +7915,159 @@ void tst_QNetworkReply::putWithRateLimiting() } +#ifndef QT_NO_SSL + +class PutWithServerClosingConnectionImmediatelyHandler: public QObject +{ + Q_OBJECT +public: + bool m_parsedHeaders; + QByteArray m_receivedData; + QByteArray m_expectedData; + QSslSocket *m_socket; + PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s) + { + m_socket->setParent(this); + connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot())); + connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot())); + } +signals: + void correctFileUploadReceived(); + void corruptFileUploadReceived(); + +public slots: + void closeDelayed() { + m_socket->close(); + } + + void readyReadSlot() + { + QByteArray data = m_socket->readAll(); + m_receivedData += data; + if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) { + m_parsedHeaders = true; + QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency + // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout + // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload + // This test catches that. + } + + } + void disconnectedSlot() + { + if (m_parsedHeaders) { + //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n")); + m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data + } + if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) { + // We had received some data but it is corrupt! + qDebug() << "CORRUPT" << m_receivedData.count(); + + // Use this to track down the pattern of the corruption and conclude the source +// QFile a("/tmp/corrupt"); +// a.open(QIODevice::WriteOnly); +// a.write(m_receivedData); +// a.close(); + +// QFile b("/tmp/correct"); +// b.open(QIODevice::WriteOnly); +// b.write(m_expectedData); +// b.close(); + //exit(1); + emit corruptFileUploadReceived(); + } else { + emit correctFileUploadReceived(); + } + } +}; + +class PutWithServerClosingConnectionImmediatelyServer: public SslServer +{ + Q_OBJECT +public: + int m_correctUploads; + int m_corruptUploads; + int m_repliesFinished; + int m_expectedReplies; + QByteArray m_expectedData; + PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0) + { + QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*))); + QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*))); + } + +public slots: + void createHandlerForConnection(QSslSocket* s) { + PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData); + handler->setParent(this); + QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect())); + QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt())); + } + void increaseCorrect() { + m_correctUploads++; + } + void increaseCorrupt() { + m_corruptUploads++; + } + void replyFinished() { + m_repliesFinished++; + if (m_repliesFinished == m_expectedReplies) { + QTestEventLoop::instance().exitLoop(); + } + } +}; + + + +void tst_QNetworkReply::putWithServerClosingConnectionImmediately() +{ + const int numUploads = 40; + qint64 wantedSize = 512*1024; // 512 kB + QByteArray sourceFile; + for (int i = 0; i < wantedSize; ++i) { + sourceFile += (char)'a' +(i%26); + } + bool withSsl = false; + + for (int s = 0; s <= 1; s++) { + withSsl = (s == 1); + // Test also needs to run several times because of 9c2ecf89 + for (int j = 0; j < 20; j++) { + // emulate a minimal https server + PutWithServerClosingConnectionImmediatelyServer server; + server.m_ssl = withSsl; + server.m_expectedData = sourceFile; + server.m_expectedReplies = numUploads; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + for (int i = 0; i < numUploads; i++) { + // create the request + QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i)); + QNetworkRequest request(url); + QNetworkReply *reply = manager.put(request, sourceFile); + connect(reply, SIGNAL(sslErrors(QList)), reply, SLOT(ignoreSslErrors())); + connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished())); + reply->setParent(&server); + } + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + + //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" < 5); + // Because actually important is that we don't get any corruption: + QCOMPARE(server.m_corruptUploads, 0); + + server.close(); + } + } + + +} + +#endif // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() From 2e5cfa1ad46ecfcfe7aea8950434bedfbbb6f43b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 20 Apr 2015 12:27:33 +0200 Subject: [PATCH 10/23] Bump version Change-Id: I9435dd001b6067464d7c04fbdf92b5b3ad546bac --- src/corelib/global/qglobal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 455582e310e..6d7874ecb6a 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -37,11 +37,11 @@ #include -#define QT_VERSION_STR "5.4.2" +#define QT_VERSION_STR "5.4.3" /* QT_VERSION is (major << 16) + (minor << 8) + patch. */ -#define QT_VERSION 0x050402 +#define QT_VERSION 0x050403 /* can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)) */ From 1b4ce37371252d54ddd08c0e5325d0385217ef26 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 27 Apr 2015 17:09:31 +0200 Subject: [PATCH 11/23] Blacklist task258920_mouseBorder on Mac The test keeps failing, perfectly when run singly btw. However the approach of sending mouse move events is inherently fragile due to the use of QCursor::setPos and the expectation that that produces the correct sequence of mouse move events. Change-Id: I12ba1afcfd3fab965b8f93d5def48b435fd2ff33 Reviewed-by: Andy Shaw --- tests/auto/widgets/widgets/qmenu/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/widgets/widgets/qmenu/BLACKLIST diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST new file mode 100644 index 00000000000..de49d5ff459 --- /dev/null +++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST @@ -0,0 +1,2 @@ +[task258920_mouseBorder] +osx From d0eba497c1c34d35ddda2b5d44902ebd636d4f9e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 29 Apr 2015 09:05:06 +0200 Subject: [PATCH 12/23] configure: Change default of CFG_REDUCE_RELOCATIONS to "no". Suppress QMAKE_LFLAGS_BSYMBOLIC_FUNC (-Bsymbolic-functions for g++) by default since it causes crashes with gcc 5.X. Since applications compiled with gcc 5.X might run against Qt compiled with gcc 4.9.X and CLANG might also be affected, turn it off by default. Task-number: QTBUG-45755 Change-Id: I5704c3156db6b6f74e1c14576e5d02bcbd3082a4 Reviewed-by: Simon Hausmann Reviewed-by: BogDan Vatra --- configure | 2 +- tools/configure/configureapp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 6ce6753e3fa..15a75bbccda 100755 --- a/configure +++ b/configure @@ -674,7 +674,7 @@ CFG_SSE4_1=auto CFG_SSE4_2=auto CFG_AVX=auto CFG_AVX2=auto -CFG_REDUCE_RELOCATIONS=auto +CFG_REDUCE_RELOCATIONS=no CFG_ACCESSIBILITY=auto CFG_ACCESSIBILITY_ATSPI_BRIDGE=no # will be enabled depending on dbus and accessibility being enabled CFG_NEON=auto diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 6e9d4aa80be..db0791b75ce 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1696,7 +1696,7 @@ void Configure::applySpecSpecifics() dictionary[ "LARGE_FILE" ] = "no"; dictionary[ "ANGLE" ] = "no"; dictionary[ "DYNAMICGL" ] = "no"; - dictionary[ "REDUCE_RELOCATIONS" ] = "yes"; + dictionary[ "REDUCE_RELOCATIONS" ] = "no"; dictionary[ "QT_GETIFADDRS" ] = "no"; dictionary[ "QT_XKBCOMMON" ] = "no"; dictionary["ANDROID_STYLE_ASSETS"] = "yes"; From 518f886b6128331ce47932edd637471d58d0d877 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Fri, 17 Apr 2015 10:43:19 +0200 Subject: [PATCH 13/23] Revert "Rotate images according to Exif orientation" Due to a behavior change. This reverts commit 9157087334186ff3ef811f2ec234a3bf5d4a4889. This reverts commit 16c32c6dfbca03a46d1a2bb87b6c1c365e6179d5. Task-number: QTBUG-37946 Task-number: QTBUG-45552 Task-number: QTBUG-43563 Change-Id: Idf8df7d8f22465e8f6b51acb68993ac97208b184 Reviewed-by: Konstantin Ritt Reviewed-by: Gunnar Sletta --- src/gui/image/qjpeghandler.cpp | 150 +----------------- .../images/jpeg_exif_orientation_value_1.jpg | Bin 910 -> 0 bytes .../images/jpeg_exif_orientation_value_2.jpg | Bin 910 -> 0 bytes .../images/jpeg_exif_orientation_value_3.jpg | Bin 988 -> 0 bytes .../images/jpeg_exif_orientation_value_4.jpg | Bin 995 -> 0 bytes .../images/jpeg_exif_orientation_value_5.jpg | Bin 912 -> 0 bytes .../images/jpeg_exif_orientation_value_6.jpg | Bin 911 -> 0 bytes ...jpeg_exif_orientation_value_6_motorola.jpg | Bin 911 -> 0 bytes .../images/jpeg_exif_orientation_value_7.jpg | Bin 987 -> 0 bytes .../images/jpeg_exif_orientation_value_8.jpg | Bin 991 -> 0 bytes tests/auto/gui/image/qimage/tst_qimage.cpp | 33 ---- 11 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg delete mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 9cf9947b6c2..14c8b4c0f46 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -726,7 +726,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), exifOrientation(1), iod_src(0), state(Ready), q(qq) + : quality(75), iod_src(0), state(Ready), q(qq) {} ~QJpegHandlerPrivate() @@ -741,10 +741,8 @@ public: bool readJpegHeader(QIODevice*); bool read(QImage *image); - void applyExifOrientation(QImage *image); int quality; - int exifOrientation; QVariant size; QImage::Format format; QSize scaledSize; @@ -762,97 +760,6 @@ public: QJpegHandler *q; }; -static bool readExifHeader(QDataStream &stream) -{ - char prefix[6]; - if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix)) - return false; - if (prefix[0] != 'E' || prefix[1] != 'x' || prefix[2] != 'i' || prefix[3] != 'f' || prefix[4] != 0 || prefix[5] != 0) - return false; - return true; -} - -/* - * Returns -1 on error - * Returns 0 if no Exif orientation was found - * Returns 1 orientation is horizontal (normal) - * Returns 2 mirror horizontal - * Returns 3 rotate 180 - * Returns 4 mirror vertical - * Returns 5 mirror horizontal and rotate 270 CCW - * Returns 6 rotate 90 CW - * Returns 7 mirror horizontal and rotate 90 CW - * Returns 8 rotate 270 CW - */ -static int getExifOrientation(QByteArray &exifData) -{ - QDataStream stream(&exifData, QIODevice::ReadOnly); - - if (!readExifHeader(stream)) - return -1; - - quint16 val; - quint32 offset; - - // read byte order marker - stream >> val; - if (val == 0x4949) // 'II' == Intel - stream.setByteOrder(QDataStream::LittleEndian); - else if (val == 0x4d4d) // 'MM' == Motorola - stream.setByteOrder(QDataStream::BigEndian); - else - return -1; // unknown byte order - - // read size - stream >> val; - if (val != 0x2a) - return -1; - - stream >> offset; - // we have already used 8 bytes of TIFF header - offset -= 8; - - // read IFD - while (!stream.atEnd()) { - quint16 numEntries; - - // skip offset bytes to get the next IFD - if (stream.skipRawData(offset) != (qint32)offset) - return -1; - - stream >> numEntries; - - for (;numEntries > 0; --numEntries) { - quint16 tag; - quint16 type; - quint32 components; - quint16 value; - quint16 dummy; - - stream >> tag >> type >> components >> value >> dummy; - if (tag == 0x0112) { // Tag Exif.Image.Orientation - if (components !=1) - return -1; - if (type != 3) // we are expecting it to be an unsigned short - return -1; - if (value < 1 || value > 8) // check for valid range - return -1; - - // It is possible to include the orientation multiple times. - // Right now the first value is returned. - return value; - } - } - - // read offset to next IFD - stream >> offset; - if (offset == 0) // this is the last IFD - break; - } - - // No Exif orientation was found - return 0; -} /*! \internal */ @@ -872,7 +779,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); - jpeg_save_markers(&info, JPEG_APP0+1, 0xFFFF); // Exif uses APP1 marker (void) jpeg_read_header(&info, TRUE); @@ -884,8 +790,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) format = QImage::Format_Invalid; read_jpeg_format(format, &info); - QByteArray exifData; - for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) { if (marker->marker == JPEG_COM) { QString key, value; @@ -903,18 +807,9 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) description += key + QLatin1String(": ") + value.simplified(); readTexts.append(key); readTexts.append(value); - } else if (marker->marker == JPEG_APP0+1) { - exifData.append((const char*)marker->data, marker->data_length); } } - if (exifData.size()) { - // Exif data present - int orientation = getExifOrientation(exifData); - if (orientation > 0) - exifOrientation = orientation; - } - state = ReadHeader; return true; } @@ -928,48 +823,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) return true; } -void QJpegHandlerPrivate::applyExifOrientation(QImage *image) -{ - // This is not an optimized implementation, but easiest to maintain - QTransform transform; - - switch (exifOrientation) { - case 1: // normal - break; - case 2: // mirror horizontal - *image = image->mirrored(true, false); - break; - case 3: // rotate 180 - transform.rotate(180); - *image = image->transformed(transform); - break; - case 4: // mirror vertical - *image = image->mirrored(false, true); - break; - case 5: // mirror horizontal and rotate 270 CCW - *image = image->mirrored(true, false); - transform.rotate(270); - *image = image->transformed(transform); - break; - case 6: // rotate 90 CW - transform.rotate(90); - *image = image->transformed(transform); - break; - case 7: // mirror horizontal and rotate 90 CW - *image = image->mirrored(true, false); - transform.rotate(90); - *image = image->transformed(transform); - break; - case 8: // rotate 270 CW - transform.rotate(-90); - *image = image->transformed(transform); - break; - default: - qWarning("This should never happen"); - } - exifOrientation = 1; -} - bool QJpegHandlerPrivate::read(QImage *image) { if(state == Ready) @@ -981,7 +834,6 @@ bool QJpegHandlerPrivate::read(QImage *image) if (success) { for (int i = 0; i < readTexts.size()-1; i+=2) image->setText(readTexts.at(i), readTexts.at(i+1)); - applyExifOrientation(image); state = Ready; return true; diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg deleted file mode 100644 index aaa4ac4e10f40e6a32560aef43b553e804f0a973..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 910 zcmex=@c%Z0 zGe`$T0AvV727omGKg1x&!NA49#mp$kz$D1XEXer(2!j~dJ0O?B06POGP+XFcfr%O9 z5d>gkVrF6ee~Wz(=SUhmhk>$zLYFZ;^Qy*Xp@!!9$`S)MazOgeKTC9?CS%G6(;wklud z*8?q*2U*0x$bzs5=n+PC239sf0U<@OWlSK;7+4uJ9kip4IA${*U~Ndh;=oeN(b1R2 z@hmMZea)X&em+k+RA)(4vY%7x(!8uvc=GAoUzsV>O1si$WnQk(s=Tm(RaJ{IYMK&* zlJd;YAP)k=0~~Ac5CH`s8>4^_G(_0!nZoV6S4G?jw>(++tL*7>F_y&N`@^?SQH?Px zl-_b%H1pZ#&oLcUcHVbpv`%p-4Y|*15}D6^JUlf&*Yvu-ao4ZRrO$k8MQk?;$9y;G z?9JxrZF5PBo4)V&ccArRpy)sajPSUyR}{TIo!P$icWIex`Wm+NuekhyjsnLlSeHNv zKhOwKL0|--0H_I|$Pw^faBSzpY#Eny2S?MYosLecR)a!Y45$ZH6C(q}T2LSh*vWgX zm{6$Bz$E=-){a-n<}c5K>=8iI!oa8i4I`kI;#YER*`^&=LApid+04N35 AMF0Q* diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg deleted file mode 100644 index a61d2723d7cf43ee9244f4dcb6b26d848574a480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 910 zcmex=>Y?(AtXBkCs161k%1ZL zPh`N##>Ddf76T76BLkBFvjEVym*4elSJ@emF31klAua&21z7_dGm8LF0|zL)SedF# zo@*8=m&VTrs#O#On$Ez$$_iJ`$i%|Tz{SEB3f?O;B>8U}nWRec5HX`RX%{8Fcm}D@-|a=DWw4GgFtixb9vO zy&D9+-v?PK0JH-oNSIleSlJi_grR}LX3uoocJk)8ewn#!;^x^-oatBB@TSf?)zrl7 zwq{3lG+Wgvv1RM$h+KPmeR-_QEeGED?}TP9+ho}mnX<&1N3Lzfam%xI6P6iztmz1v zGHJ>Q&(oXd{J!bE_kAtUb}>+NAbbmCF*3ko!(NeDxnkYrBt{Ww$9lsm#Z{+bfNlcE zEI5b+82Eukhzp{}C@|$f%mBrW0B0$Sj0ocb1qP?Yea_K6W=6T^>Veusf!a_kW?+P9 z0tK>w+XE(xbM9d$y!aVjFdmu1nGe(->>Kn<)5C;n#;;;xvy%_1)O>qVvO I_5W`I093Zmxc~qF diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg deleted file mode 100644 index 43e56dcef70bbd6cf48fae727ea5f6cb4d63061e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 988 zcmex=>Y?(AtWa|2T)uB=t*Xf zM-YI8jf3<5Ee0N-Fp~hY0MNI=ya{gaK05#Dyz!p_s7G7?WDi0E0|N^iI|EP)2Pni? znJ#WoK4ZOk%hH{Hw{D%81J)uZ2(pEV8KI4liG>-ci&arT5Udj@WzYDhx7%IYQ0J@} z&l&$O(=0VrCV!b!H>qy&^T^Wa(f6DK>kir#p|#jj3gK zy;7L%uzKm~!`{gmWj7*cnVIRWTTvbpA8#_7L+2i!-j)>(W+%^1=el~Uy0!2a-|gOy zcTW47oXjhWO!?6%^2VU()=|SV(Gjhhx=8}lw!Y8Ya_0BC(74^pBU5+PKG54?zSW6= z!D=m!BS+g+H${%pwQN>lnqDqp8wKTn&J+d4CURT?<68h0m-dPi7AGB-R@YSu-L(G7 z!tf8QzyK4hQhfD`AE*SJLclpdpg|v$E(C#Ljbaod15)e?EZZ$GZ@s37h}Po(jj2I>+ML`zJ-dJtOEO@}jAme#}38+Ox0L{e=3UC(-NEPw4 c<;{yOihgMQw`8jpNA32x_o^1S*!{l=0P;Kok^lez diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg deleted file mode 100644 index d5d06f740922c4ecd4e49cd2aaa90a8293c4e108..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 995 zcmex={xcvIrKfhkD{O+;sc9na`y3^XP=J1+^ zhsyBqEt-{4!gl?_x0zedWloklq-><5dw)OBei?8;Az9A=w4RBTjX^{V8dhxfOn>4w zuWr=sOP-uABzfuS=Qi2t+pJq|uXSF&dj5s%jq5FcM4r-YYkQ+}mH7+1*}9u;wI@w3 zcAeJwETNv*Jn5O`xtygO!4gYm3oO;t&7LrQ%f0V2w=PSoy{k68^u~%=bNhWZb?IKt zWlWvMc6kxg>ju9ojts6*Jx;ROj+eGB)fVmOuLn9*Q~(h~kO*QFfW@Z0qTAz1j~bVG zIf)1RADP!twQtI=eA@!k`hsAf5^y460L7|611N2X2_kzJWELX>#3)ew3LHA;UEO0e zS@+P{2ZnKdKv`D2dO-0baAe^FJq8)i1JnGzZrO4=+3W;JivZY8kohnmUZda0FylhIRF3v diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg deleted file mode 100644 index 1886f3775e047d42bb5ffb2af704f84434af336b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 912 zcmex=>Y?(AtXBoCs16Rk%1ZH z4+LOhW?}n(i-89y%p|}p0QBq?f!eYRncJt1cdQ2LkQ88GLe;{;4io|D;Q)mgE7Q8Q zyt`)XR+$|B8K_)Z5M%+e21X_pW&uG(L$C&BMn-$ab-UKDn!RpWciy(%)tgRzyVSLM zRj+iG=CayGz_tXO| zk^@`B#Ka8u3eYEvZ0rJptU`)lyO=aUf)`s*e4lK1C9ersW&(hM; z*Zlc-bCWlF$~PW^vo?XQ=PY9;9#;yt+2n10?%vF2vr0NNg%>(-d4(`-)p22PaW_5= zv{nWZ90*$(m|2)u*%%oFgrFh9X3w;B>G^KeIY)!NO0VYKeEc?k{-F|yc0s8P;rX+< zGp)|Po5&!wZJ%bycU2P!#i%SB{u$vi32%4Yvo<=NyD4(+v`AYmS8E=bO%r{J#ex*Q zJiSupEVVqn>3#KUpaaAN7?3Ond!A7M78&-6O?8vx5+BOv?%nkHI%D{ER(_xqIBvnZ z1RnH*j1UB-8+fpR7(nNPjQ~ZDfcK03osW}J0%reBNVi!M5VC6Ze7u@K;VfV$@3mq= yp*ql(!jjB_8)ts$1NDdspxMK~r~r4WK=ivr$7{z#%~w>Y?(AtXBoCs16Rk%1ZH z4+LOhVP*S&i-89y%p|}p0QBtTXKedox}W7<(R^eN)FL4O)PkyqnT?4BsD}d-VysL@ zU#n}Ln7)6N2~e?|Ajo`1R)l&+CKhIPRyF}eLqV_>pjq~ep&^U`46E!#!!Iz@gvv88 zUtqrQ@#H3Nc9kL?gR?e)uJ``lR4F{!SA1G!^Vip(=4CEF8myy!SjA`Kag~@)XF~;@ z8f@x;wn>3(0|F%9FtaeS3P5aP0@<`~*ZNhn*RAT#-PRtSI(6ri(9n<#b6rg?JTlwY zzUAz?VvifwBqb*b=KVaHxV`^mw$F@X#R|z1hb|i%PjyL4i(ca5x_e3VZV>o>9%!Si z00R@ygGgb>%)-RV#>gNbC=3k|HhZScC-?SU(4DpN7ngL*J@M4^2&tpRKZ>p{vIq!> zT5vvc!`5pnIj_%jeR=(KBip3EvpG*cb6wUG7MX77beKnGvf;VnP%Wn!N7YlDrfi)DJX5To5(TfJO*H%>c!Y0P|iA8HR>O3=T{M_EY?R_qLo228Fg5NE;%kk!%Kq zv_Sq5;TMOML%SxmH|$_2RA-6-Y7r4Y)xf}@0C%c@Xw1nQUHpf8_MBRAbn6F&tM&hH F0sz;@-NOI? diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6_motorola.jpg deleted file mode 100644 index 0aa164b78b986bec1177bbac2ac5a181c5423a3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 911 zcmex=q=O;=GK3-nK$`y_Vi4qD;9}rnW)x@ci+Wc+`GK@992h+82fI|nCFT%3`C z8R$hMz{JAJ_Wu?G4^Ws%fLQ?O$IH*y_QiBR%e|uc$R4OgLI9`*RSz>86AMre2Pni? znU20z*E}(O|0)xpVmU#O`HZXx^^8m`%={Et7y}qq*^7o>V5kX| zXJEd-eBtBCP2TJ(MLY&)Z312I{k^GDc(Skfw94kMuRqPpTz)iINByvh&&J~_F`v$c z3OY5|)B|mk0@(%x2=6d4voNv>Kx|?H*|cug`c<>nt?JI*)*hZZb?21O(2xytT}>`L zGTYa_$}=|x&fuY zaSKkr0!;ltBg6$!0}W_|Ak+*{>ywSyfxM$C)6-T#zP`FzE G|0V$P?A^-% diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg deleted file mode 100644 index b3dcc466a907a504db72fa83957326bfcc5aac78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 987 zcmex=>Y?(AtXB|7f@V+k%1ZL zPh`Nt#=-gj76T76BLkBFvjEVyD;s9!tyXc4ynVj56{tsC0AvrU7Ip@p77kE|u`*rQ zlI|mGd9UWm*R5M;=KN;>YLOEJTEoDEWECS53o{!#1FNEdAXq0*%AWD#;@-}*X=!OH zo6RJ}RQ{?=+JDLOm*+44=aHq;qwin)TU&a!_K@zjdxA%`H=X*ieBq*1uNGf8xK-q` z+XcJb7x%6E^>*93TiJ_^cZ;d~1llSKvK7UHOw25dtPE`IP)nIWmVWYI_E(KFtxbNx z?<0Y(Rw;d!w(EDBZ1T1`YJAq@5i^R)_rJ90KM_j6b?i2+^Cvs$hk~b_e?G-1i=`)tpd?Tr{Uo zx|O;?Ip_tt&|u52V|C-?FNFmU_!wk74=@3BhzOu*U{HX&S3v5KAy>Lm Z^@`#H;nhnfX))AppL?%rfs5V$n*d6*1>67t diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg deleted file mode 100644 index 8bc390e2b9a7e8704f824eaedf0248a2181b6650..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 991 zcmex=w%gi1sIrsvPgi1oq?H+6{w2? z6lknWiBi`e^Vg|MgnsNelE88Rs7Fo^Xb}Sw6Ej>FBNGcV13Q}{tAHR_BhVf8j8Epy zylLQVV(?9Tj;l!UW0k^_PwTC1HhJ4+_k8xX3ttxD-{vthxzB6o(^;#OS{Z61Q@dlm zwq9DbC2!U0eG5a~dKehYA23ugR58y7S}F^+6lgHqu}sV?j6e@EK<#7#+4*yhKHp`t z?VXP$jtLs}qzKKNIq#+9%t>21I<}W|mxDn4{&}g-;_~Zf|NMHr^1H{j+g0u%>rQLG zn!{@v9xB7bw`f*I3ETAx-)3$-mpNJLkg}1I?*08B`yl~^6jng%nONBv1cb$)fyHLe zR36>^=hz{Kc+VL}(kI`jPEkJh^lQoCsBQBL=UctW{v!DzamBJSQK=|%r{hO&J=>V( zb2(i_@% diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 309d3a80c5b..33302edfeb3 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -173,9 +173,6 @@ private slots: void invertPixelsRGB_data(); void invertPixelsRGB(); - void exifOrientation_data(); - void exifOrientation(); - void cleanupFunctions(); private: @@ -2649,36 +2646,6 @@ void tst_QImage::invertPixelsRGB() QCOMPARE(qBlue(pixel) >> 4, (255 - 96) >> 4); } -void tst_QImage::exifOrientation_data() -{ - QTest::addColumn("fileName"); - QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg"; - QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg"; - QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg"; - QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg"; - QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg"; - QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg"; - QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg"; - QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg"; - QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg"; -} - -void tst_QImage::exifOrientation() -{ - QFETCH(QString, fileName); - - QImage img; - QRgb px; - - QVERIFY(img.load(fileName)); - - px = img.pixel(0, 0); - QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5); - - px = img.pixel(img.width() - 1, 0); - QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250); -} - static void cleanupFunction(void* info) { bool *called = static_cast(info); From 225270978786a19eccd60fee0097d866ec0a9d78 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 20 Apr 2015 10:35:37 -0700 Subject: [PATCH 14/23] Add the changelog for 5.4.2 Change-Id: I27eaacb532114dd188c4ffff13d6c95e1026b99d Reviewed-by: Gunnar Sletta Reviewed-by: Simon Hausmann --- dist/changes-5.4.2 | 107 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 dist/changes-5.4.2 diff --git a/dist/changes-5.4.2 b/dist/changes-5.4.2 new file mode 100644 index 00000000000..e1ad9b68466 --- /dev/null +++ b/dist/changes-5.4.2 @@ -0,0 +1,107 @@ +Qt 5.4.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.4.1. Compatibility with Qt +5.4.0 is also retained, except on Windows when using MSVC 2012 or MSVC +2013. See note below. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5.4/ + +The Qt version 5.4 series is binary compatible with the 5.3.x series. +Applications compiled for 5.3 will continue to run with 5.4 with the +exception of on Windows when using MSVC 2012 or MSVC 2013. See note +below. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** +- Restored binary compatibility with Qt 5.3.2 on Windows when using MSVC + 2012 or MSVC 2013. This means that Qt 5.4.1 and 5.4.2 are no longer + binary compatible with Qt 5.4.0 when using either of those compilers. +- [QTBUG-42594] OS X binary package: fixed incorrect linking to libraries in + /opt/local/lib +- EXIF orientation is no longer applied to JPEG images on read. EXIF + orientation on JPEG was introduced in 5.4.0, but due to a bug the most + common EXIF-format (big-endian) was not working until 5.4.1. 5.4.2 restores the + behavior of 5.4.0 and earlier for most EXIF-tagged JPEGs. + EXIF orientation will be an opt-in starting with Qt 5.5. + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + - [QTBUG-43893] Fixed memory leak in qSetMessagePattern + - [QTBUG-43513] QXmlStreamReader: Correctly parse XML containing NUL bytes + in the input stream + - [QTBUG-43352] QTemporaryDirectory: Properly clean up in case of a failure + - [QTBUG-43827] Fixed regression in QSortFilterProxyModel which crashed when + sorting a tree model + +QtGui +----- + - [QTBUG-44273] Fixed misplacement of outlined text with native text rendering + - [QTBUG-44147] Fixed VNC not working on some VNC servers + - [QTBUG-43850] Fixed crash with multi-threaded font usage + - [QTBUG-43850] Made the old harfbuzz fallback available at runtime + - Improvements to the experimental high-dpi support + - [QTBUG-43318] Better resolution of GLES 3 functions to avoid issues when + deploying on systems with GLES 2.0 only + +QtWidgets +--------- + - [QTBUG-43830] Fixed crash in stylesheets when styling QProgressBar + - [QTBUG-43663] QColorDialog: Don't lose focus while color picking + +QtNetwork +--------- + - [QTBUG-43793] Fixed disconnects of QSSLSocket after starting encryption + +QtPrintSupport +-------------- + - [QTBUG-43124] Fixed QPrinter::{width,height} return values + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Android +------- + + - [QTBUG-44648] Fixed rendering Chinese text on Android 5 + +Linux/XCB +--------- + + - [QTBUG-45071] Don't crash when resizing windows to bigger than 3840x2160 + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - CMake-based projects using Qt will now always be built with -fPIE, + which fixes function pointer based QObject::connect() on ARM. This + is consistent with qmake + - [Android] Fixed compilation on armv5 with 4.9 toolchain + +qmake +----- + + - [VS] Fixed handling of files that are excluded from build + - [QTBUG-44413][VS] Fixed vcxproj generation for CONFIG-=flat, again + - [QTBUG-44595] Restored Qt 4 behavior of qtLibraryTarget() + - [QTBUG-45118][Windows] Fixed parallel build when using TYPELIBS + - [OS X/iOS] Fixed QMAKE_INFO_PLIST path resolution for shadow builds From ef622d55ca990e70f60d11964fa2f3651ccd4522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Fri, 24 Apr 2015 17:13:39 +0200 Subject: [PATCH 15/23] Android: Use Holo theme on Android 5.1 We already fallback to the Holo theme on Android 5.0 devices, see: 7c539579b9e883c87e5f7fb3bbec80847fc83ae2 Task-number: QTBUG-45714 Change-Id: I18b0700321b27ab5bbe3f1642a0bc9de1774864a Reviewed-by: BogDan Vatra --- .../java/src/org/qtproject/qt5/android/bindings/QtActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java index 75f10ad3bae..a790e0ef6f2 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -187,7 +187,7 @@ public class QtActivity extends Activity QT_ANDROID_THEMES = new String[] {"Theme_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Light"; } - else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT == 21){ + else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT >= 21){ QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light"; } else { From 119c5ec93f3b32cb62456c3a42c54ebb2c42e567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Fri, 24 Apr 2015 15:21:21 +0200 Subject: [PATCH 16/23] Android: Fix wrong field name in ExtractStyle.java In Android 5.1 the field name for the inset state member in InsetDrawable changed from mInsetState to mState. Task-number: QTBUG-45714 Change-Id: I0ebada1ef90954013e5357cbd10df925f8f05295 Reviewed-by: BogDan Vatra --- .../jar/src/org/qtproject/qt5/android/ExtractStyle.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index a8583cde17e..79722183bf3 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1100,7 +1100,9 @@ public class ExtractStyle { { try { InsetDrawable d = (InsetDrawable)drawable; - Object mInsetStateObject = getAccessibleField(InsetDrawable.class, "mInsetState").get(d); + // mInsetState changed to mState in Android 5.1 (22) + Object mInsetStateObject = getAccessibleField(InsetDrawable.class, (Build.VERSION.SDK_INT > 21) ? "mState" + : "mInsetState").get(d); Rect _padding = new Rect(); boolean hasPadding = d.getPadding(_padding); return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null); From 1f281bfd63402b50f3db378a027da26ca52ffb27 Mon Sep 17 00:00:00 2001 From: Christoph Schleifenbaum Date: Sat, 18 Apr 2015 14:39:18 +0200 Subject: [PATCH 17/23] ItemViews: Fix acceptance of drag enter events Always accept drag enter events if the mime type and the drop actions matches. Whether the drop can actually happen on the currently hovered index will be decided in the following drag move event. Change-Id: I27e865cb65513dfe3f57ad3f1bc8cebf4c29a692 Task-number: QTBUG-45037 Reviewed-by: David Faure --- src/widgets/itemviews/qabstractitemview_p.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index c3bd1fb504d..be5d4b7b710 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -168,8 +168,20 @@ public: QModelIndex index; int col = -1; int row = -1; + const QMimeData *mime = event->mimeData(); + + // Drag enter event shall always be accepted, if mime type and action match. + // Whether the data can actually be dropped will be checked in drag move. + if (event->type() == QEvent::DragEnter) { + const QStringList modelTypes = model->mimeTypes(); + for (int i = 0; i < modelTypes.count(); ++i) + if (mime->hasFormat(modelTypes.at(i)) + && (event->dropAction() & model->supportedDropActions())) + return true; + } + if (dropOn(event, &row, &col, &index)) { - return model->canDropMimeData(event->mimeData(), + return model->canDropMimeData(mime, dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(), row, col, index); } From 4db5d3ccd17d448b59db491e2f261892f31fec74 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Mon, 10 Nov 2014 12:04:56 +0100 Subject: [PATCH 18/23] Fix shortcuts when using setDefaultAction Don't remove ampersands when setting the text: they will be removed when the text is displayed. This fixes double removal of ampersands. [ChangeLog][QtWidgets][QToolButton] Fix double removal of ampersands Task-number: QTBUG-23396 Change-Id: I56bf50eb24aae32a81d614824aca0b63363587c8 Reviewed-by: Timur Pocheptsov --- src/widgets/widgets/qtoolbutton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp index bb3f2d74a8b..e897b578c37 100644 --- a/src/widgets/widgets/qtoolbutton.cpp +++ b/src/widgets/widgets/qtoolbutton.cpp @@ -897,7 +897,7 @@ void QToolButton::setDefaultAction(QAction *action) return; if (!actions().contains(action)) addAction(action); - setText(action->iconText()); + setText(action->text()); setIcon(action->icon()); #ifndef QT_NO_TOOLTIP setToolTip(action->toolTip()); From b64e87f2ed6457b11594e9f4fc522860caa737ab Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 7 May 2015 13:10:13 +0200 Subject: [PATCH 19/23] Blacklist task256322_highlight on OS X The test keeps failing. The approach of sending mouse move events is inherently fragile due to the use of QCursor::setPos and the expectation that that produces the correct sequence of mouse move events. Change-Id: I07ec75460b70c27152e8775deffcb77fa9328d0c Reviewed-by: Simon Hausmann --- tests/auto/widgets/widgets/qmenubar/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/widgets/widgets/qmenubar/BLACKLIST diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST new file mode 100644 index 00000000000..e8b49454956 --- /dev/null +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -0,0 +1,2 @@ +[task256322_highlight] +osx From ace86dca159d50886be5bcff7abe72383cad9fde Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 7 May 2015 08:34:19 +0200 Subject: [PATCH 20/23] Revert "configure: Change default of CFG_REDUCE_RELOCATIONS to "no"." This reverts commit d0eba497c1c34d35ddda2b5d44902ebd636d4f9e. A better fix is to use -fPIC instead of just -fPIE fo -reduce-relocations. Task-number: QTBUG-45755 Change-Id: I1759291b684fd76d4009e4be9ba1354eb056e659 Reviewed-by: Simon Hausmann Reviewed-by: Thiago Macieira --- configure | 2 +- tools/configure/configureapp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 15a75bbccda..6ce6753e3fa 100755 --- a/configure +++ b/configure @@ -674,7 +674,7 @@ CFG_SSE4_1=auto CFG_SSE4_2=auto CFG_AVX=auto CFG_AVX2=auto -CFG_REDUCE_RELOCATIONS=no +CFG_REDUCE_RELOCATIONS=auto CFG_ACCESSIBILITY=auto CFG_ACCESSIBILITY_ATSPI_BRIDGE=no # will be enabled depending on dbus and accessibility being enabled CFG_NEON=auto diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index db0791b75ce..6e9d4aa80be 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1696,7 +1696,7 @@ void Configure::applySpecSpecifics() dictionary[ "LARGE_FILE" ] = "no"; dictionary[ "ANGLE" ] = "no"; dictionary[ "DYNAMICGL" ] = "no"; - dictionary[ "REDUCE_RELOCATIONS" ] = "no"; + dictionary[ "REDUCE_RELOCATIONS" ] = "yes"; dictionary[ "QT_GETIFADDRS" ] = "no"; dictionary[ "QT_XKBCOMMON" ] = "no"; dictionary["ANDROID_STYLE_ASSETS"] = "yes"; From 36d6eb721e7d5997ade75e289d4088dc48678d0d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 5 May 2015 08:43:42 -0700 Subject: [PATCH 21/23] Require -fPIC instead of just -fPIE for -reduce-relocations GCC 5 combined with a recent binutils have a new optimization that allows them to generate copy relocations even in -fPIE code. Clang has the same functionality when compiling an executable with -flto. We need to let the compilers know that they cannot use copy relocations, so they need to use really position-independent code. Position independent code throughout is not really required. We just need the compilers to use position-independent access to symbols coming from the Qt libraries, but there's currently no other way of doing that. Task-number: QTBUG-45755 Change-Id: I0d4913955e3745b69672ffff13db5df7377398c5 Reviewed-by: Simon Hausmann Reviewed-by: Oswald Buddenhagen --- mkspecs/common/gcc-base.conf | 2 +- mkspecs/common/qcc-base.conf | 2 +- mkspecs/linux-icc/qmake.conf | 2 +- src/corelib/Qt5CoreConfigExtras.cmake.in | 2 +- src/corelib/global/qglobal.h | 4 ++-- tests/auto/tools/moc/tst_moc.cpp | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mkspecs/common/gcc-base.conf b/mkspecs/common/gcc-base.conf index a149f4d9072..e4ccbd7156b 100644 --- a/mkspecs/common/gcc-base.conf +++ b/mkspecs/common/gcc-base.conf @@ -42,7 +42,7 @@ QMAKE_CFLAGS_RELEASE += $$QMAKE_CFLAGS_OPTIMIZE QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_SHLIB += -fPIC QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_APP += -fPIE +QMAKE_CFLAGS_APP += -fPIC QMAKE_CFLAGS_ISYSTEM = -isystem QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden diff --git a/mkspecs/common/qcc-base.conf b/mkspecs/common/qcc-base.conf index f529d7fc7ba..8276316c3fe 100644 --- a/mkspecs/common/qcc-base.conf +++ b/mkspecs/common/qcc-base.conf @@ -23,7 +23,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_SHLIB += -fPIC -shared QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_APP += -fPIE +QMAKE_CFLAGS_APP += -fPIC QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden QMAKE_CFLAGS_SSE2 += -msse2 diff --git a/mkspecs/linux-icc/qmake.conf b/mkspecs/linux-icc/qmake.conf index 8119c8aa09d..9190aa9f28c 100644 --- a/mkspecs/linux-icc/qmake.conf +++ b/mkspecs/linux-icc/qmake.conf @@ -12,7 +12,7 @@ QMAKE_LEXFLAGS = QMAKE_YACC = yacc QMAKE_YACCFLAGS = -d QMAKE_CFLAGS = -QMAKE_CFLAGS_APP = -fPIE +QMAKE_CFLAGS_APP = -fPIC QMAKE_CFLAGS_DEPS = -M QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261 QMAKE_CFLAGS_WARN_OFF = -w diff --git a/src/corelib/Qt5CoreConfigExtras.cmake.in b/src/corelib/Qt5CoreConfigExtras.cmake.in index 7213a844f5a..48d5f21447f 100644 --- a/src/corelib/Qt5CoreConfigExtras.cmake.in +++ b/src/corelib/Qt5CoreConfigExtras.cmake.in @@ -71,7 +71,7 @@ set(_qt5_corelib_extra_includes) # macro to add it. set(Qt5_POSITION_INDEPENDENT_CODE True) set_property(TARGET Qt5::Core PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE \"ON\") -set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIE\") +set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIC\") !!IF !isEmpty(QT_NAMESPACE) list(APPEND Qt5Core_DEFINITIONS -DQT_NAMESPACE=$$QT_NAMESPACE) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 455582e310e..ef84662036d 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1047,9 +1047,9 @@ Q_CORE_EXPORT int qrand(); # define QT_NO_SHAREDMEMORY #endif -#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__) && !defined(__PIE__) +#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__) # error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\ - "Compile your code with -fPIC or -fPIE." + "Compile your code with -fPIC." #endif namespace QtPrivate { diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index edb6488eaa2..748cb82989d 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -662,7 +662,7 @@ void tst_Moc::oldStyleCasts() QStringList args; args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "." - << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", args); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -732,7 +732,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension() QStringList args; args << "-c" << "-x" << "c++" << "-I" << ".." - << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", args); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -1011,7 +1011,7 @@ void tst_Moc::ignoreOptionClashes() // If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation. QStringList gccArgs; gccArgs << "-c" << "-x" << "c++" << "-I" << ".." - << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", gccArgs); QVERIFY(proc.waitForStarted()); proc.write(mocOut); From 00fe833189e79be3f8f00d1972d1f54b7f384dde Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 6 May 2015 12:57:58 +0200 Subject: [PATCH 22/23] QNAM: Fix compiler warning Change-Id: I2ae6493e13c9b168c64c458e42ea90d4ec2d8628 Reviewed-by: Friedemann Kleint Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/network/access/qnetworkreplyhttpimpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 974a101e9cd..a4f677efab6 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1280,7 +1280,7 @@ void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount) { if (uploadByteDevicePosition + amount != pos) { // Sanity check, should not happen. - error(QNetworkReply::UnknownNetworkError, ""); + error(QNetworkReply::UnknownNetworkError, QString()); return; } uploadByteDevice->advanceReadPointer(amount); From 3545ef41217e3ce4d1bea2b07793fa7a8c1058a6 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 4 May 2015 18:20:07 -0700 Subject: [PATCH 23/23] Autotest: Check if this D-Bus library knows about file descriptors Because if it doesn't, then calling dbus_type_is_fixed or is_basic may result in a failed assertion. process 16304: arguments to dbus_type_is_fixed() were incorrect, assertion "_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID" failed in file dbus-signature.c line 345. Change-Id: Idf715b895bac4d56b4afffff13db2ed71b1516a5 Reviewed-by: Allan Sandfeld Jensen --- tests/auto/dbus/qdbustype/tst_qdbustype.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp index e674b6d686a..a054db877d5 100644 --- a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp +++ b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp @@ -87,8 +87,19 @@ static void addFixedTypes() QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true; QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true; QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true; + #ifdef DBUS_TYPE_UNIX_FD_AS_STRING - QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; +# ifndef QT_LINKED_LIBDBUS + // We have got the macro from dbus_minimal_p.h, so we need to check if + // the library recognizes this as valid type first. + // The following function was added for Unix FD support, so if it is + // present, so is support for Unix FDs. + bool supportsUnixFds = qdbus_resolve_conditionally("dbus_connection_can_send_type"); +# else + bool supportsUnixFds = true; +# endif + if (supportsUnixFds) + QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; #endif }