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

QAbstractItemModel crashes if model item contains QPersistentModelIndex of that item

    XMLWordPrintable

Details

    • Linux/X11
    • ef7773e5664dd8278831ed4d7d24dd4fc1aaefd3

    Description

      If an item in a model contains an QPersistentModelIndex of that item, the program crashes on mass model item removal.

      Seems the reason is that QStandardItemModelPrivate::rowsRemoved() deletes the model item (which results in deletion of the persistent index in the model) and then calls the QAbstractItemModelPrivate::rowsRemoved() which tries to access the deleted persistent index.

      To reproduce, run the test program, click on the "Add items" button and then on the "Clear items" - the program should crash.

      Test program
      #include <QApplication>
      #include <QHBoxLayout>
      #include <QListView>
      #include <QMainWindow>
      #include <QPushButton>
      #include <QStandardItemModel>
      #include <QVBoxLayout>
      
      const int g_createCount = 100;
      
      int main(int argc, char *argv[])
      {   
          QApplication app(argc, argv);
      
          QMainWindow mainWindow;
          QStandardItemModel *model = new QStandardItemModel(&mainWindow);
      
          QListView *view = new QListView();
          view->setModel(model);
      
          QPushButton *addButton = new QPushButton("Add items");
          QPushButton *clearButton = new QPushButton("Clear items");
      
          QVBoxLayout *buttonsLayout = new QVBoxLayout;
          buttonsLayout->addStretch(1);
          buttonsLayout->addWidget(addButton);
          buttonsLayout->addWidget(clearButton);
          buttonsLayout->addStretch(1);
      
          QHBoxLayout *mainLayout = new QHBoxLayout;
          mainLayout->addWidget(view);
          mainLayout->addLayout(buttonsLayout);
      
          QWidget *centralWidget = new QWidget;
          centralWidget->setLayout(mainLayout);
      
          mainWindow.setCentralWidget(centralWidget);
      
          QObject::connect(addButton, &QAbstractButton::clicked, &mainWindow, [model]()
          {
              for (int i = 0; i < g_createCount; ++i)
              {
                  auto item = new QStandardItem;
                  model->appendRow(item);
      
                  QPersistentModelIndex index = model->indexFromItem(item);
                  item->setData(QVariant::fromValue(i), Qt::DisplayRole);
                  item->setData(QVariant::fromValue(index), Qt::UserRole + 1);
              }
          });
      
          QObject::connect(clearButton, &QAbstractButton::clicked, &mainWindow, [model]()
          {
              model->removeRows(0, model->rowCount());
          });
      
          mainWindow.show();
      
          return app.exec();
      }
      

      Valgrind Memcheck found invalid read/write errors for the test program, I've attached the output of one such case.

      Attachments

        1. qtbug78142.zip
          2 kB
        2. valgrind.txt
          11 kB
        For Gerrit Dashboard: QTBUG-78142
        # Subject Branch Project Status CR V

        Activity

          People

            dfaure_kdab David Faure
            nkrupenko.nvidia Nikita Krupenko
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes