summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/tinycbor/tests/parser/data.cpp37
-rw-r--r--src/corelib/serialization/qcborstreamreader.cpp35
-rw-r--r--src/corelib/serialization/qcborvalue.cpp27
-rw-r--r--src/corelib/text/qbytearray_p.h7
-rw-r--r--src/testlib/qabstractitemmodeltester.cpp6
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp12
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp8
7 files changed, 91 insertions, 41 deletions
diff --git a/src/3rdparty/tinycbor/tests/parser/data.cpp b/src/3rdparty/tinycbor/tests/parser/data.cpp
index 0ab0e47be4..3523c32167 100644
--- a/src/3rdparty/tinycbor/tests/parser/data.cpp
+++ b/src/3rdparty/tinycbor/tests/parser/data.cpp
@@ -338,7 +338,7 @@ void addValidationColumns()
QTest::addColumn<CborError>("expectedError");
}
-void addValidationData()
+void addValidationData(size_t minInvalid = ~size_t(0))
{
// illegal numbers are future extension points
QTest::newRow("illegal-number-in-unsigned-1") << raw("\x81\x1c") << 0 << CborErrorIllegalNumber;
@@ -488,26 +488,35 @@ void addValidationData()
QTest::newRow("map-break-after-value-tag2") << raw("\x81\xbf\0\xd8\x20\xff") << 0 << CborErrorUnexpectedBreak;
// check for pointer additions wrapping over the limit of the address space
- CborError tooLargeOn32bit = (sizeof(void *) == 4) ? CborErrorDataTooLarge : CborErrorUnexpectedEOF;
+ auto wraparoundError = [minInvalid](uint64_t encodedSize) {
+ if (encodedSize > minInvalid)
+ return CborErrorDataTooLarge;
+ return CborErrorUnexpectedEOF;
+ };
+ constexpr uint64_t FourGB = UINT32_MAX + UINT64_C(1);
// on 32-bit systems, this is a -1
- QTest::newRow("bytearray-wraparound1") << raw("\x81\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
- QTest::newRow("string-wraparound1") << raw("\x81\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
+ QTest::newRow("bytearray-wraparound1") << raw("\x81\x5a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
+ QTest::newRow("string-wraparound1") << raw("\x81\x7a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
// on 32-bit systems, a 4GB addition could be dropped
- QTest::newRow("bytearray-wraparound2") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
- QTest::newRow("string-wraparound2") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
+ QTest::newRow("bytearray-wraparound2") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
+ QTest::newRow("string-wraparound2") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
// on 64-bit systems, this could be a -1
- QTest::newRow("bytearray-wraparound3") << raw("\x81\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
- QTest::newRow("string-wraparound3") << raw("\x81\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
+ QTest::newRow("bytearray-wraparound3") << raw("\x81\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
+ << wraparoundError(UINT64_MAX);
+ QTest::newRow("string-wraparound3") << raw("\x81\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
+ << wraparoundError(UINT64_MAX);
// ditto on chunks
- QTest::newRow("bytearray-chunk-wraparound1") << raw("\x81\x5f\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
- QTest::newRow("string-chunk-wraparound1") << raw("\x81\x7f\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
+ QTest::newRow("bytearray-chunk-wraparound1") << raw("\x81\x5f\x5a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
+ QTest::newRow("string-chunk-wraparound1") << raw("\x81\x7f\x7a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
// on 32-bit systems, a 4GB addition could be dropped
- QTest::newRow("bytearray-chunk-wraparound2") << raw("\x81\x5f\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
- QTest::newRow("string-chunk-wraparound2") << raw("\x81\x7f\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
+ QTest::newRow("bytearray-chunk-wraparound2") << raw("\x81\x5f\x5b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
+ QTest::newRow("string-chunk-wraparound2") << raw("\x81\x7f\x7b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
// on 64-bit systems, this could be a -1
- QTest::newRow("bytearray-chunk-wraparound3") << raw("\x81\x5f\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
- QTest::newRow("string-chunk-wraparound3") << raw("\x81\x7f\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
+ QTest::newRow("bytearray-chunk-wraparound3") << raw("\x81\x5f\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
+ << wraparoundError(UINT64_MAX);
+ QTest::newRow("string-chunk-wraparound3") << raw("\x81\x7f\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
+ << wraparoundError(UINT64_MAX);
QTest::newRow("eof-after-array") << raw("\x81") << 0 << CborErrorUnexpectedEOF;
QTest::newRow("eof-after-array2") << raw("\x81\x78\x20") << 0 << CborErrorUnexpectedEOF;
diff --git a/src/corelib/serialization/qcborstreamreader.cpp b/src/corelib/serialization/qcborstreamreader.cpp
index c983436606..ec385e0629 100644
--- a/src/corelib/serialization/qcborstreamreader.cpp
+++ b/src/corelib/serialization/qcborstreamreader.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 Intel Corporation.
+** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -42,6 +42,7 @@
#define CBOR_NO_ENCODER_API
#include <private/qcborcommon_p.h>
+#include <private/qbytearray_p.h>
#include <private/qnumeric_p.h>
#include <private/qutfcodec_p.h>
#include <qdebug.h>
@@ -1055,6 +1056,10 @@ bool QCborStreamReader::next(int maxRecursion)
} else if (isString() || isByteArray()) {
auto r = _readByteArray_helper();
while (r.status == Ok) {
+ if (isString() && r.data.size() > MaxStringSize) {
+ d->handleError(CborErrorDataTooLarge);
+ break;
+ }
if (isString() && !QUtf8::isValidUtf8(r.data, r.data.size()).isValidUtf8) {
d->handleError(CborErrorInvalidUtf8TextString);
break;
@@ -1337,15 +1342,23 @@ QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
result.status = r.status;
if (r.status == Ok) {
- QTextCodec::ConverterState cs;
- result.data = QUtf8::convertToUnicode(r.data, r.data.size(), &cs);
- if (cs.invalidChars == 0 && cs.remainingChars == 0)
- return result;
+ // See QUtf8::convertToUnicode() a detailed explanation of why this
+ // conversion uses the same number of words or less.
+ CborError err = CborNoError;
+ if (r.data.size() > MaxStringSize) {
+ err = CborErrorDataTooLarge;
+ } else {
+ QTextCodec::ConverterState cs;
+ result.data = QUtf8::convertToUnicode(r.data, r.data.size(), &cs);
+ if (cs.invalidChars != 0 || cs.remainingChars != 0)
+ err = CborErrorInvalidUtf8TextString;
+ }
- d->handleError(CborErrorInvalidUtf8TextString);
- result.data.clear();
- result.status = Error;
- return result;
+ if (err) {
+ d->handleError(err);
+ result.data.clear();
+ result.status = Error;
+ }
}
return result;
}
@@ -1373,6 +1386,10 @@ QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_he
qsizetype len = _currentStringChunkSize();
if (len < 0)
return result;
+ if (len > MaxByteArraySize) {
+ d->handleError(CborErrorDataTooLarge);
+ return result;
+ }
result.data.resize(len);
auto r = readStringChunk(result.data.data(), len);
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index 98161094ae..63ee5f3158 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 Intel Corporation.
+** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -53,6 +53,7 @@
#include <qendian.h>
#include <qlocale.h>
+#include <private/qbytearray_p.h>
#include <private/qnumeric_p.h>
#include <private/qsimd_p.h>
@@ -1553,6 +1554,8 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// and calculate the final size
if (add_overflow(offset, increment, &newSize))
return -1;
+ if (newSize > MaxByteArraySize)
+ return -1;
// since usedData <= data.size(), this can't overflow
usedData += increment;
@@ -1627,13 +1630,6 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
setErrorInReader(reader, { QCborError::DataTooLarge });
}
- if (r.status == QCborStreamReader::Error) {
- // There can only be errors if there was data to be read.
- Q_ASSERT(e.flags & Element::HasByteData);
- data.truncate(e.value);
- return;
- }
-
// update size
if (e.flags & Element::HasByteData) {
auto b = new (dataPtr() + e.value) ByteData;
@@ -1645,6 +1641,21 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
Q_ASSERT(e.type == QCborValue::String);
e.flags |= Element::StringIsAscii;
}
+
+ // check that this UTF-8 text string can be loaded onto a QString
+ if (e.type == QCborValue::String) {
+ if (Q_UNLIKELY(b->len > MaxStringSize)) {
+ setErrorInReader(reader, { QCborError::DataTooLarge });
+ r.status = QCborStreamReader::Error;
+ }
+ }
+ }
+
+ if (r.status == QCborStreamReader::Error) {
+ // There can only be errors if there was data to be read.
+ Q_ASSERT(e.flags & Element::HasByteData);
+ data.truncate(e.value);
+ return;
}
elements.append(e);
diff --git a/src/corelib/text/qbytearray_p.h b/src/corelib/text/qbytearray_p.h
index 3c6257f786..ffec6dca22 100644
--- a/src/corelib/text/qbytearray_p.h
+++ b/src/corelib/text/qbytearray_p.h
@@ -56,10 +56,9 @@
QT_BEGIN_NAMESPACE
-enum {
- // Define as enum to force inlining. Don't expose MaxAllocSize in a public header.
- MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type)
-};
+// -1 because of the terminating NUL
+constexpr qsizetype MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type) - 1;
+constexpr qsizetype MaxStringSize = (MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type)) / 2 - 1;
QT_END_NAMESPACE
diff --git a/src/testlib/qabstractitemmodeltester.cpp b/src/testlib/qabstractitemmodeltester.cpp
index 2e05097122..a09d007a82 100644
--- a/src/testlib/qabstractitemmodeltester.cpp
+++ b/src/testlib/qabstractitemmodeltester.cpp
@@ -288,6 +288,12 @@ QAbstractItemModelTester::FailureReportingMode QAbstractItemModelTester::failure
return d->failureReportingMode;
}
+bool QAbstractItemModelTester::verify(bool statement, const char *statementStr, const char *description, const char *file, int line)
+{
+ Q_D(QAbstractItemModelTester);
+ return d->verify(statement, statementStr, description, file, line);
+}
+
QAbstractItemModelTesterPrivate::QAbstractItemModelTesterPrivate(QAbstractItemModel *model, QAbstractItemModelTester::FailureReportingMode failureReportingMode)
: model(model),
failureReportingMode(failureReportingMode),
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index ebef36d033..f8784f9428 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -1844,10 +1844,16 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
|| edit(index, NoEditTriggers, event))
return;
- if (d->selectionMode != SingleSelection)
- topLeft = d->pressedPosition - d->offset();
- else
+ if (d->selectionMode != SingleSelection) {
+ // Use the current selection start index if it is valid as this will be based on the
+ // start of the selection and not the last item being pressed which can be different
+ // when in extended selection
+ topLeft = d->currentSelectionStartIndex.isValid()
+ ? visualRect(d->currentSelectionStartIndex).center()
+ : d->pressedPosition - d->offset();
+ } else {
topLeft = bottomRight;
+ }
d->checkMouseMove(index);
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 0239856ed9..48e407f917 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -505,7 +505,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
if (QApplicationPrivate::inPopupMode()) {
- QWidget *activePopupWidget = QApplication::activePopupWidget();
+ QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
QPoint mapped = event->pos();
if (activePopupWidget != m_widget)
mapped = activePopupWidget->mapFromGlobal(event->globalPos());
@@ -565,9 +565,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
#endif
if ((event->type() != QEvent::MouseButtonPress)
|| !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) {
-
+ // if the widget that was pressed is gone, then deliver move events without buttons
+ const auto buttons = event->type() == QEvent::MouseMove && qt_button_down == nullptr
+ ? Qt::NoButton : event->buttons();
QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers(), event->source());
+ event->button(), buttons, event->modifiers(), event->source());
e.setTimestamp(event->timestamp());
QApplicationPrivate::sendMouseEvent(receiver, &e, receiver, receiver->window(), &qt_button_down, qt_last_mouse_receiver);
qt_last_mouse_receiver = receiver;