[PATCH] QSortFilterProxyModel: don't call index(row, 0) if there are no columns
authorDavid Faure <david.faure@kdab.com>
Mon, 3 Mar 2025 18:14:59 +0000 (19:14 +0100)
committerPatrick Franz <deltaone@debian.org>
Wed, 16 Apr 2025 19:33:04 +0000 (21:33 +0200)
This is invalid, e.g. it asserts in
QConcatenateTablesProxyModel::index()

Fixes: QTBUG-134210
Change-Id: I21acad9497d423b0366991296e8dd498d51395ea
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 93694e99c214a5166fc842f92659e42260230dce)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Gbp-Pq: Name upstream_prevent_recursion_in_qsortfilterproxymodel.diff

src/corelib/itemmodels/qsortfilterproxymodel.cpp
tests/auto/corelib/itemmodels/qconcatenatetablesproxymodel/tst_qconcatenatetablesproxymodel.cpp

index 4076487d24a9b4038d348382ecda6b0d358e0ba2..ce42882c62e13261833bd9ef7eb5fcc3155cdab3 100644 (file)
@@ -434,6 +434,10 @@ bool QSortFilterProxyModelPrivate::recursiveChildAcceptsRow(int source_row, cons
 {
     Q_Q(const QSortFilterProxyModel);
 
+    const int colCount = model->columnCount(source_parent);
+    if (colCount == 0) // don't call index(row, 0) if there's no such column
+        return false;
+
     const QModelIndex index = model->index(source_row, 0, source_parent);
     const int count = model->rowCount(index);
 
index b15ba191e5d2143f2123890c37f6199e21bac103..1d0f6645ecd8855b05058ab5d2129f7d345b0306 100644 (file)
@@ -83,6 +83,7 @@ private Q_SLOTS:
     void shouldPropagateDropBetweenItemsAtModelBoundary();
     void shouldPropagateDropAfterLastRow_data();
     void shouldPropagateDropAfterLastRow();
+    void addModelWithFilterOnTop();
     void qtbug91788();
     void qtbug91878();
     void createPersistentOnLayoutAboutToBeChanged();
@@ -860,6 +861,39 @@ void tst_QConcatenateTablesProxyModel::shouldPropagateDropAfterLastRow()
 
 }
 
+class RefuseRowsProxy : public QSortFilterProxyModel
+{
+public:
+    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
+    {
+        Q_UNUSED(source_row)
+        Q_UNUSED(source_parent)
+        return false;
+    }
+};
+
+void tst_QConcatenateTablesProxyModel::addModelWithFilterOnTop() // QTBUG-134210
+{
+    // Given a QSFPM -> QConcatenateTablesProxyModel and a QStandardItemModel
+    QStandardItemModel sim;
+    sim.appendRow(new QStandardItem("ITEM"));
+
+    QConcatenateTablesProxyModel concat;
+    RefuseRowsProxy proxyFilter;
+    proxyFilter.setSourceModel(&concat);
+    proxyFilter.setRecursiveFilteringEnabled(true);
+
+    // When adding the QStandardItemModel as source model
+    concat.addSourceModel(&sim);
+
+    // Then the item should be filtered out
+    // (without hitting an assert in QConcat::index() nor an infinite recursion in QSFPM)
+    QCOMPARE(concat.rowCount(), 1);
+    QCOMPARE(concat.columnCount(), 1);
+    QCOMPARE(proxyFilter.rowCount(), 0);
+    QCOMPARE(proxyFilter.columnCount(), 1);
+}
+
 void tst_QConcatenateTablesProxyModel::qtbug91788()
 {
     QConcatenateTablesProxyModel proxyConcat;