tst_QHeaderView: fix UB (invalid downcast) in testStylePosition()

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 <axel.spoerl@qt.io>
Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
(cherry picked from commit 8beaab9483405603ffb17a3472bef8dd088227ff)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2025-03-26 14:01:53 +01:00 committed by Qt Cherry-pick Bot
parent 9c9146a5cd
commit 99032b8fa8
2 changed files with 14 additions and 13 deletions

View File

@ -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;

View File

@ -3335,32 +3335,30 @@ void tst_QHeaderView::testStylePosition()
topLevel->show();
QVERIFY(QTest::qWaitForWindowExposed(topLevel));
protected_QHeaderView *header = static_cast<protected_QHeaderView *>(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);
}