Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.5.3
-
None
Description
Expected QAbstractItemModel behavior can cause an assert in QQmlDelegateModel.
Set up a model so the root index has a child and so that child has a child. Provide that model to a DelegateModel, and set the root index of the DelegateModel to the grandchild of the source model. Then remove the first row from the root index of the source model.
Source model structure:
Root index
Child index <- Row removed
Grandchild index <- Root index of the DelegateModel
Removing the row will invalidate the QPersistentModelIndex for the grandchild that is stored as the root index of the QQmlDelegateModel. Then a slot in QQmlDelegateModel responds to the QAbstractItemModel::rowsRemoved signal. This slot will only proceed if the parent index from the signal equals its stored QPeristentModelIndex. In this situation, the parent index is an invalid QModelIndex (since a row is being removed from the root of the source model), and the QPersistentModelIndex has been invalidated. The equality check is true since they're both invalid, so code execution proceeds and attempts to remove an item from the QQmlDelegateModel. However, the grandchild never had any children, so it's attempting to remove a row from zero. This makes the count of the QQmlDelegateModel negative, causing an assert.
This assert was added in https://codereview.qt-project.org/gitweb?p=qt/qtdeclarative.git;a=commitdiff;h=d70b4ab2e58bcfd5e65c1d11a79020bb3e2906c0
The code doesn't crash if you ignore the assert. However, this seems like an issue, and I wouldn't be surprised if it would cause more problems down the line for that DelegateModel.
I have attached a sample Qt6.5.3 project that can reproduce this issue. It uses a timer with five seconds to remove the row and cause the assertion.