From 99032b8fa8039bc9235b3011a42e0c9862a4c7f2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 26 Mar 2025 14:01:53 +0100 Subject: [PATCH] tst_QHeaderView: fix UB (invalid downcast) in testStylePosition() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The view that's being created in init() is not a protected_QHeaderView, but only a "normal" QHeaderView, so casting it to protected_QHeaderView is not valid. Says UBSan: tst_qheaderview.cpp:3338:37: runtime error: downcast of address 0x604000087050 which does not point to an object of type 'protected_QHeaderView' 0x604000087050: note: object is of type 'QHeaderView' 00 00 00 00 d8 d2 e6 0b b2 7f 00 00 80 88 00 00 c0 61 00 00 08 d6 e6 0b b2 7f 00 00 00 00 be be ^~~~~~~~~~~~~~~~~~~~~~~ vptr for 'QHeaderView' Fix using the usual trick: forward-declare tst_QHeaderView and make QHeaderView itself befriend it directly. Amends bff78163f6dc83d833b2097a51453523cfa7b00b. tst_QHeaderView is now asan/ubsan-clean, except for some signed overflows in calculateAndCheck(), filed QTBUG-135201 to track it. Pick-to: 6.8 6.5 5.15 Change-Id: I718695bef26e72f442bd677c6bad05bab561163f Reviewed-by: Axel Spoerl Reviewed-by: Thorbjørn Lund Martsum (cherry picked from commit 8beaab9483405603ffb17a3472bef8dd088227ff) Reviewed-by: Qt Cherry-pick Bot --- src/widgets/itemviews/qheaderview.h | 3 +++ .../itemviews/qheaderview/tst_qheaderview.cpp | 24 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/widgets/itemviews/qheaderview.h b/src/widgets/itemviews/qheaderview.h index bd0050df5ef..07475257433 100644 --- a/src/widgets/itemviews/qheaderview.h +++ b/src/widgets/itemviews/qheaderview.h @@ -9,6 +9,8 @@ QT_REQUIRE_CONFIG(itemviews); +class tst_QHeaderView; + QT_BEGIN_NAMESPACE class QHeaderViewPrivate; @@ -209,6 +211,7 @@ protected: friend class QTableView; friend class QTreeView; + friend class ::tst_QHeaderView; private: void initStyleOption(QStyleOptionFrame *option) const override; diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 3d96ad1afc0..77584175ce0 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -3335,32 +3335,30 @@ void tst_QHeaderView::testStylePosition() topLevel->show(); QVERIFY(QTest::qWaitForWindowExposed(topLevel)); - protected_QHeaderView *header = static_cast(view); - TestStyle proxy; - header->setStyle(&proxy); + view->setStyle(&proxy); QImage image(1, 1, QImage::Format_ARGB32); QPainter p(&image); // 0, 1, 2, 3 - header->paintSection(&p, view->rect(), 0); + view->paintSection(&p, view->rect(), 0); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); - header->paintSection(&p, view->rect(), 1); + view->paintSection(&p, view->rect(), 1); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); - header->paintSection(&p, view->rect(), 2); + view->paintSection(&p, view->rect(), 2); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); - header->paintSection(&p, view->rect(), 3); + view->paintSection(&p, view->rect(), 3); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); // (0),2,1,3 view->setSectionHidden(0, true); view->swapSections(1, 2); - header->paintSection(&p, view->rect(), 1); + view->paintSection(&p, view->rect(), 1); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); - header->paintSection(&p, view->rect(), 2); + view->paintSection(&p, view->rect(), 2); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); - header->paintSection(&p, view->rect(), 3); + view->paintSection(&p, view->rect(), 3); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); // (1),2,0,(3) @@ -3368,14 +3366,14 @@ void tst_QHeaderView::testStylePosition() view->setSectionHidden(0, false); view->setSectionHidden(1, true); view->swapSections(0, 1); - header->paintSection(&p, view->rect(), 0); + view->paintSection(&p, view->rect(), 0); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); - header->paintSection(&p, view->rect(), 2); + view->paintSection(&p, view->rect(), 2); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); // (1),2,(0),(3) view->setSectionHidden(0, true); - header->paintSection(&p, view->rect(), 2); + view->paintSection(&p, view->rect(), 2); QCOMPARE(proxy.lastPosition, QStyleOptionHeader::OnlyOneSection); }