Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-44611

QItemSelectionProxyModel crashes due to not updating its persistent indexes

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • P2: Important
    • None
    • 5.4.0
    • Widgets: Itemviews
    • None
    • Mac OS X 10.9.5, Qt 5.3.2, Qt 5.4.0, Qt be35b9f

    Description

      I have a fairly complex hierarchy of nested models, and I have no idea if this is relevant (from source to proxy):

      MyListModel -> MySortModel -> MyFilterModel -> MyIdentityModel -> MyIdentityModel2

      The FilterModel also makes some columns editable and directly modifies the underlying data-source.

      This hierarchy is the model of a tree view.

      When I edit one of the columns in the model, QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged triggers QItemSelectionProxyModel::_q_layoutAboutToBeChanged, which saves some persistent indexes.

      In the subsequent call of QSortFilterProxyModelPrivate::_q_sourceLayoutChanged its persistent indexes are cleared (update_persistent_indexes) and QItemSelectionModelPrivate::_q_layoutChanged is triggered, which does not update its own persistent indexes.

      Therefor mergeRowLengths uses invalid persistent indexes, which leads to the following crash, since the internal pointer to the Mapping-iterator is no longer valid:

      0	QSortFilterProxyModel::sibling(int, int, QModelIndex const&) const	QSortFilterProxyModel::sibling(int, int, QModelIndex const&) const		0x102211507	
      1	QIdentityProxyModel::sibling(int, int, QModelIndex const&) const	QIdentityProxyModel::sibling(int, int, QModelIndex const&) const		0x102205178	
      2	QIdentityProxyModel::sibling(int, int, QModelIndex const&) const	QIdentityProxyModel::sibling(int, int, QModelIndex const&) const		0x102205178	
      3	QPersistentModelIndex::sibling(int, int) const	QPersistentModelIndex::sibling(int, int) const		0x1021e9be5	
      4	mergeRowLengths(QVector<QPair<QPersistentModelIndex, unsigned int>> const&)	mergeRowLengths(QVector<QPair<QPersistentModelIndex, unsigned int> > const&)		0x1021fdd05	
      5	QItemSelectionModelPrivate::_q_layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QItemSelectionModelPrivate::_q_layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x1021fd409	
      6	QItemSelectionModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)	QItemSelectionModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)		0x102201249	
      7	QMetaObject::activate(QObject*, int, int, void**)	QMetaObject::activate(QObject*, int, int, void**)		0x10226e9db	
      8	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x1022e9df3	
      9	QIdentityProxyModelPrivate::_q_sourceLayoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QIdentityProxyModelPrivate::_q_sourceLayoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x102206f1c	
      10	QIdentityProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)	QIdentityProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)		0x1022074d0	
      11	QMetaObject::activate(QObject*, int, int, void**)	QMetaObject::activate(QObject*, int, int, void**)		0x10226e9db	
      12	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x1022e9df3	
      13	QIdentityProxyModelPrivate::_q_sourceLayoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QIdentityProxyModelPrivate::_q_sourceLayoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x102206f1c	
      14	QIdentityProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)	QIdentityProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)		0x1022074d0	
      15	QMetaObject::activate(QObject*, int, int, void**)	QMetaObject::activate(QObject*, int, int, void**)		0x10226e9db	
      16	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x1022e9df3	
      17	QSortFilterProxyModelPrivate::_q_sourceLayoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QSortFilterProxyModelPrivate::_q_sourceLayoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x10220f73a	
      18	QSortFilterProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)	QSortFilterProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)		0x102213d03	
      19	QMetaObject::activate(QObject*, int, int, void**)	QMetaObject::activate(QObject*, int, int, void**)		0x10226e9db	
      20	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)	QAbstractItemModel::layoutChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint)		0x1022e9df3	
      21	QSortFilterProxyModelPrivate::_q_sourceDataChanged(QModelIndex const&, QModelIndex const&)	QSortFilterProxyModelPrivate::_q_sourceDataChanged(QModelIndex const&, QModelIndex const&)		0x10220e1ce	
      22	QSortFilterProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)	QSortFilterProxyModel::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)		0x102213c93	
      23	QMetaObject::activate(QObject*, int, int, void**)	QMetaObject::activate(QObject*, int, int, void**)		0x10226e9db	
      24	QAbstractItemModel::dataChanged(QModelIndex const&, QModelIndex const&, QVector<int> const&)	QAbstractItemModel::dataChanged(QModelIndex const&, QModelIndex const&, QVector<int> const&)		0x1022e9d1d	
      25	QpObjectListModelBase::objectUpdated(QSharedPointer<QObject>)	objectlistmodel.cpp	200	0x100503c29	
      26	QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QSharedPointer<QObject>>, void, void (QpObjectListModelBase::*)(QSharedPointer<QObject>)>::call(void (QpObjectListModelBase::*)(QSharedPointer<QObject>), QpObjectListModelBase*, void**)	qobjectdefs_impl.h	500	0x10050678a	
      27	void QtPrivate::FunctionPointer<void (QpObjectListModelBase::*)(QSharedPointer<QObject>)>::call<QtPrivate::List<QSharedPointer<QObject>>, void>(void (QpObjectListModelBase::*)(QSharedPointer<QObject>), QpObjectListModelBase*, void**)	qobjectdefs_impl.h	519	0x1005066d0	
      28	QtPrivate::QSlotObject<void (QpObjectListModelBase::*)(QSharedPointer<QObject>), QtPrivate::List<QSharedPointer<QObject>>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*)	qobject_impl.h	143	0x1005065f8	
      29	QMetaObject::activate(QObject*, int, int, void**)	QMetaObject::activate(QObject*, int, int, void**)		0x10226e5f2	
      30	QpDataAccessObjectBase::objectUpdated(QSharedPointer<QObject>)	moc_dataaccessobject.cpp	291	0x100533ad2	
      31	QpDataAccessObjectBase::updateObject(QSharedPointer<QObject>)	dataaccessobject.cpp	334	0x1004c2e4f	
      32	QpStorage::update(QSharedPointer<QObject>)	storage.cpp	320	0x1005292a9	
      33	Qp::UpdateResult QpStorage::update<libdBase2::CustomerPallet>(QSharedPointer<libdBase2::CustomerPallet>)	storage.h	164	0x10030bc7d	
      34	Qp::UpdateResult Qp::update<libdBase2::CustomerPallet>(QSharedPointer<libdBase2::CustomerPallet>)	defaultstorage.h	50	0x10030b823	
      35	libdBase2::CustomerPalletsModel::setData(QModelIndex const&, QVariant const&, int)	customerPalletsModel.cpp	129	0x10030b284	
      36	QSortFilterProxyModel::setData(QModelIndex const&, QVariant const&, int)	QSortFilterProxyModel::setData(QModelIndex const&, QVariant const&, int)		0x102211826	
      37	QSortFilterProxyModel::setData(QModelIndex const&, QVariant const&, int)	QSortFilterProxyModel::setData(QModelIndex const&, QVariant const&, int)		0x102211826	
      38	QAbstractProxyModel::setData(QModelIndex const&, QVariant const&, int)	QAbstractProxyModel::setData(QModelIndex const&, QVariant const&, int)		0x1021f6794	
      39	QAbstractProxyModel::setData(QModelIndex const&, QVariant const&, int)	QAbstractProxyModel::setData(QModelIndex const&, QVariant const&, int)		0x1021f6794	
      ...	<More>				
      

      I was not able to reproduce the bug with a simple example, but I was able to "fix" the bug by updating the QItemSelectionModel persistent indexes with something like the following being called in _q_layoutChanged:

      void QItemSelectionModelPrivate::updatePersistentIndexes()
      {
          QVector<QPersistentModelIndex> _savedPersistentIndexes;
          for(int i = 0; i < savedPersistentIndexes.size(); ++i) {
              QModelIndex old_index = savedPersistentIndexes.at(i);
              _savedPersistentIndexes << model->index(old_index.row(), old_index.column());
          }
          savedPersistentIndexes = _savedPersistentIndexes;
      
          QVector<QPersistentModelIndex> _savedPersistentCurrentIndexes;
          for(int i = 0; i < savedPersistentCurrentIndexes.size(); ++i) {
              QModelIndex old_index = savedPersistentCurrentIndexes.at(i);
              _savedPersistentCurrentIndexes << model->index(old_index.row(), old_index.column());
          }
          savedPersistentCurrentIndexes = _savedPersistentCurrentIndexes;
      
          QVector<QPair<QPersistentModelIndex, uint> > _savedPersistentRowLengths;
          for(int i = 0; i < savedPersistentRowLengths.size(); ++i) {
              QModelIndex old_index = savedPersistentRowLengths.at(i).first;
              _savedPersistentRowLengths << qMakePair(QPersistentModelIndex(model->index(old_index.row(), old_index.column())),
                                                          savedPersistentRowLengths.at(i).second);
          }
          savedPersistentRowLengths = _savedPersistentRowLengths;
      
          QVector<QPair<QPersistentModelIndex, uint> > _savedPersistentCurrentRowLengths;
          for(int i = 0; i < savedPersistentCurrentRowLengths.size(); ++i) {
              QModelIndex old_index = savedPersistentCurrentRowLengths.at(i).first;
              _savedPersistentCurrentRowLengths << qMakePair(QPersistentModelIndex(model->index(old_index.row(), old_index.column())),
                                                          savedPersistentCurrentRowLengths.at(i).second);
          }
          savedPersistentCurrentRowLengths = _savedPersistentCurrentRowLengths;
      
          currentIndex = model->index(currentIndex.row(), currentIndex.column());
          tableParent = model->index(tableParent.row(), tableParent.column());
      }
      

      Attachments

        Issue Links

          Activity

            People

              steveire Stephen Kelly (Personal)
              kampfgnom Niklas Wulf
              Votes:
              3 Vote for this issue
              Watchers:
              9 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: