(fix) avoid crash after removing Quick Link#14556
Conversation
|
I can split the commit into the actual workaround and other tweaks if desired. edit Done. |
3ed110b to
2107c57
Compare
| TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); | ||
| if (!(item && item->getData().isValid())) { | ||
| TreeItem* pItem = static_cast<TreeItem*>(index.internalPointer()); | ||
| if (!(pItem && pItem->getData().isValid())) { |
There was a problem hiding this comment.
Interestingly, if I add various qDebug() calls (log item data and label etc.), the item pointer seems to remain intact and the existing qDebug() call below doesn't crash anymore 🤷
Would the delete management of std::shared_ptr/unique_ptr instead of plain * keep the item intact?
There was a problem hiding this comment.
I have no clue what could be the reason. The internalPointer() is however a void* only without smart pointer capabilities. You get here only the address where the object has been when stored. There is no smart grantee, that the object TreeItem is still there. The pointer is only "borrowed", someone else need to take care that the object is kept valid.
There was a problem hiding this comment.
Okay.
I removed the call as it was unnecessary in the first place, so I think this is ready.
We just need to make sure not to call it after/while modifying the tree.
0feb1f4 to
0c42129
Compare
0c42129 to
2abde9b
Compare
… have been removed
2abde9b to
848e0b8
Compare
|
Can someone reprodue this bug or does it only happen with my outdated Qt 6.2.3? If the former, shall I move the other (non-critical) fixes to another PR so this one has a better chance to get into 2.5.1? |
|
I have already a review in progress. |
daschuer
left a comment
There was a problem hiding this comment.
For my understanding is that the root cause if the crash is the borrowed InternalPointer() in QModelIndex.
All later checks are pointless, because they succeed either (the pointer will never be null) or are also crashing because of call to the internal printer hidden behind the QT API.
The solution presented here to clear the stored value after using works only if it is actually used.
But there is no guarantee that such an action happens.
It would be better, if we effectively clear the pointer whenever the side bar tree structure is edited and there's a chance for a dangling pointer.
This seems to be more safe than all other not working checks.
I have not looked into a possible implementation but if you like, I can do a PR to your branch.
- Use only m_lastRightClickIndex
- Listen to a model changes we signal or such and reset the value
- Temove misleading checks (make them asserts)
What do you think?
| @@ -77,6 +77,7 @@ class BrowseFeature : public LibraryFeature { | |||
| // Caution: Make sure this is reset whenever the library tree is updated, | |||
| // so that the internalPointer() does not become dangling | |||
| TreeItem* m_pLastRightClickedItem; | |||
There was a problem hiding this comment.
This is a "borrowed" pointer that becomes dangling if the tree item is removed.
| // Caution: Make sure this is reset whenever the library tree is updated, | ||
| // so that the internalPointer() does not become dangling | ||
| TreeItem* m_pLastRightClickedItem; | ||
| QModelIndex m_pLastRightClickedIndex; |
There was a problem hiding this comment.
This is the index, containing the borrowed pointer above as InternalPointer().
I think the name "InternalPointer is already a hint, that the it shall not be used externally.
But anyway with a bit of control we can.
|
Thanks for taking a look!
Yes, please. I think I get the idea, but I'm not sure about the QModelIndex <--> TreeItem relation. IIUC the issue would be fixed if we'd listen to the tree model's signals |
|
Here it is: |
This avoids using an no longer existing QMdodelndex() with a danging pointer.
| connect(m_pSidebarModel, | ||
| &QAbstractItemModel::modelAboutToBeReset, | ||
| this, | ||
| &BrowseFeature::invalidateRightClickIndex); |
There was a problem hiding this comment.
This breaks slotRefreshDirectoryTree() where we call
onLazyChildExpandation(m_lastRightClickedIndex);
TreeItemModel::insertTreeItemRows() has now an invalid index (invalid parent TreeItem) and inserts the new rows at row 0.
Apparently it's not required to reset the QModelIndex in that case since onLazyChildExpandation(index) works flawlessly even tough this also alters the model (below the index).
Possible fixes:
- revert this commit -- and test all cases that caused crashes earlier
(see 1.12 removing a quick link can lead to crash #8270 / crash when deleting directory from Computer -> Quick Links #12817) - in
slotRefreshDirectoryTree(), copym_lastRightClickedIndexand callonLazyChildExpandation(copy)-- works, no crash
@daschuer What do you think?
workaround for #8270, happening with Qt 6.2.3
(... and other minor fixes for BrowseFeature, please see individual commits)
Apparently, the checks for
item != nullptranditem->getData().isValid()don't suffice.The crash happens afterwards with
qDebug() << item->getLabel() << item->getData().toString(), so apparently the item has been removed in the meantime.Simply don't call
onLazyChildExpandation()after the context menu was closed and a Quick Link might have been removed.Tbh I don't understand reasoning to expand the item after the menu closed in the first place. Regardless if the menu is used or closed right away, this is basically expand on right-click.
I removed those calls entirely, simply to avoid any further surprises.
Another bug I noticed while working on #14514 is that "Refresh directory tree" doesn't work for items other than first-level child items (and probably never did 😬 since #12908).
Fixed by using the last right-clicked index, too, as we do in other library features.