diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 4c394339294..89c4617fb02 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -34,6 +34,14 @@ QT_BEGIN_NAMESPACE +Q_DECL_COLD_FUNCTION +static void warn_overflow(const char *caller, const char *callee, int value) +{ + qWarning("Integer argument %d causes overflow in %s when calling %s, " + "results may not be as you expect", + value, caller, callee); +} + #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionItem §ion) { @@ -408,10 +416,18 @@ void QHeaderView::setOffset(int newOffset) // don't overflow; this function is checked with both INT_MIN and INT_MAX... const int ndelta = q26::saturate_cast(d->headerOffset - qint64{newOffset}); d->headerOffset = newOffset; - if (d->orientation == Qt::Horizontal) - d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0); - else + if (d->orientation == Qt::Horizontal) { + if (isLeftToRight()) { + if (int r; !qMulOverflow<-1>(ndelta, &r)) + d->viewport->scroll(r, 0); + else + warn_overflow("QHeaderView::setOffset", "QWidget::scroll", newOffset); + } else { + d->viewport->scroll(ndelta, 0); + } + } else { d->viewport->scroll(0, ndelta); + } if (d->state == QHeaderViewPrivate::ResizeSection && !d->preventCursorChangeInSetOffset) { QPoint cursorPos = QCursor::pos(); if (d->orientation == Qt::Horizontal) diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index b8b750d13e3..ddba11fb5fd 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -381,6 +381,22 @@ public: bool m_bMultiLine = false; }; +static Qt::LayoutDirection otherLayoutDirection(Qt::LayoutDirection current) +{ + switch (current) { + case Qt::LayoutDirection::LeftToRight: return Qt::LayoutDirection::RightToLeft; + case Qt::LayoutDirection::RightToLeft: return Qt::LayoutDirection::LeftToRight; + case Qt::LayoutDirection::LayoutDirectionAuto: + ; + } + Q_UNREACHABLE_RETURN(Qt::LayoutDirection::LayoutDirectionAuto); +} + +static void swapLayoutDirection(QWidget &w) +{ + w.setLayoutDirection(otherLayoutDirection(w.layoutDirection())); +} + // Testing get/set functions void tst_QHeaderView::getSetCheck() { @@ -426,9 +442,20 @@ void tst_QHeaderView::getSetCheck() QCOMPARE(0, obj1.offset()); obj1.setOffset(std::numeric_limits::min()); QCOMPARE(std::numeric_limits::min(), obj1.offset()); + QTest::ignoreMessage(QtWarningMsg, // one of the INT_MAX will hit this; not necessarily the first one + "Integer argument 2147483647 causes overflow in QHeaderView::setOffset " + "when calling QWidget::scroll, results may not be as you expect"); obj1.setOffset(std::numeric_limits::max()); QCOMPARE(std::numeric_limits::max(), obj1.offset()); + // and again with RTL (or LTR, if it was RTL before): + swapLayoutDirection(obj1); + obj1.setOffset(0); + QCOMPARE(0, obj1.offset()); + obj1.setOffset(std::numeric_limits::min()); + QCOMPARE(std::numeric_limits::min(), obj1.offset()); + obj1.setOffset(std::numeric_limits::max()); + QCOMPARE(std::numeric_limits::max(), obj1.offset()); } tst_QHeaderView::tst_QHeaderView()