Fix crash due to QTreeView accessing deleted model indexes.

QTreeViewPrivate::updateScrollBars depends on a correctly set up
viewItems vector. If a delayed layout is pending, we must call
QTreeViewPrivate::executePostedLayout before accessing any stored model
indices.

Task-number: QTBUG-45697
Change-Id: I55fcbaf81f225b26181c2cf739283740b85dd16a
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Joerg Bornemann 2015-05-27 12:27:19 +02:00
parent 310b7ef010
commit 42b7a7c609
2 changed files with 79 additions and 0 deletions

View File

@ -3658,6 +3658,7 @@ void QTreeViewPrivate::updateScrollBars()
if (!viewportSize.isValid())
viewportSize = QSize(0, 0);
executePostedLayout();
if (viewItems.isEmpty()) {
q->doItemsLayout();
}

View File

@ -255,6 +255,7 @@ private slots:
void taskQTBUG_8176_emitOnExpandAll();
void taskQTBUG_34717_collapseAtBottom();
void taskQTBUG_37813_crash();
void taskQTBUG_45697_crash();
void testInitialFocus();
};
@ -4385,5 +4386,82 @@ void tst_QTreeView::taskQTBUG_37813_crash()
#endif // QT_BUILD_INTERNAL
}
// QTBUG-45697: Using a QTreeView with a multi-column model filtered by QSortFilterProxyModel,
// when sorting the source model while the widget is not yet visible and showing the widget
// later on, corruption occurs in QTreeView.
class Qtbug45697TestWidget : public QWidget
{
Q_OBJECT
public:
static const int columnCount = 3;
explicit Qtbug45697TestWidget();
int timerTick() const { return m_timerTick; }
public slots:
void slotTimer();
private:
QTreeView *m_treeView;
QStandardItemModel *m_model;
QSortFilterProxyModel *m_sortFilterProxyModel;
int m_timerTick;
};
Qtbug45697TestWidget::Qtbug45697TestWidget()
: m_treeView(new QTreeView(this))
, m_model(new QStandardItemModel(0, Qtbug45697TestWidget::columnCount, this))
, m_sortFilterProxyModel(new QSortFilterProxyModel(this))
, m_timerTick(0)
{
QVBoxLayout *vBoxLayout = new QVBoxLayout(this);
vBoxLayout->addWidget(m_treeView);
for (char sortChar = 'z'; sortChar >= 'a' ; --sortChar) {
QList<QStandardItem *> items;
for (int column = 0; column < Qtbug45697TestWidget::columnCount; ++column) {
const QString text = QLatin1Char(sortChar) + QLatin1String(" ") + QString::number(column);
items.append(new QStandardItem(text));
}
m_model->appendRow(items);
}
m_sortFilterProxyModel->setSourceModel(m_model);
m_treeView->setModel(m_sortFilterProxyModel);
QHeaderView *headerView = m_treeView->header();
for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s )
headerView->setSectionResizeMode(s, QHeaderView::ResizeToContents);
QTimer *timer = new QTimer(this);
timer->setInterval(50);
connect(timer, &QTimer::timeout, this, &Qtbug45697TestWidget::slotTimer);
timer->start();
}
void Qtbug45697TestWidget::slotTimer()
{
switch (m_timerTick++) {
case 0:
m_model->sort(0);
break;
case 1:
show();
break;
default:
close();
break;
}
}
void tst_QTreeView::taskQTBUG_45697_crash()
{
Qtbug45697TestWidget testWidget;
testWidget.setWindowTitle(QTest::currentTestFunction());
testWidget.resize(400, 400);
testWidget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(100, 100));
QTRY_VERIFY(testWidget.timerTick() >= 2);
}
QTEST_MAIN(tst_QTreeView)
#include "tst_qtreeview.moc"