From 0a60806f8973c05b68cf65a5a01c41d81ff2da7b Mon Sep 17 00:00:00 2001 From: Soap Frenzy <12368561+soapyf@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:25:25 -0400 Subject: #6320 Fix crash when containing object is destroyed during inventory rename When an in-world object is destroyed (via llDie, temp expiration, or deletion) while an item inside its Contents tab is being renamed, the viewer crashes with an Access Violation (0xC0000005) during LLMortician teardown. --- indra/llui/llfolderview.cpp | 48 +++++++++++++++++++++----------- indra/llui/llfolderview.h | 5 +++- indra/llui/llfolderviewitem.cpp | 12 +++++++- indra/newview/llpanelobjectinventory.cpp | 25 +++++++++++++++++ 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index baab17830b..8ece3384cd 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -257,20 +257,13 @@ LLFolderView::LLFolderView(const Params& p) // Destroys the object LLFolderView::~LLFolderView( void ) { - mRenamerTopLostSignalConnection.disconnect(); - if (mRenamer) - { - // instead of using closeRenamer remove it directly, - // since it might already be hidden - LLUI::getInstance()->removePopup(mRenamer); - } - // The release focus call can potentially call the // scrollcontainer, which can potentially be called with a partly // destroyed scollcontainer. Just null it out here, and no worries // about calling into the invalid scroll container. // Same with the renamer. mScrollContainer = NULL; + cancelRenaming(); mRenameItem = NULL; mRenamer = NULL; mStatusTextBox = NULL; @@ -655,7 +648,10 @@ void LLFolderView::commitRename( const LLSD& data ) // since this can be called from 'focus lost' event. // Ex: clicking inworld should commit the rename. finishRenamingItem(); - arrange( NULL, NULL ); + if (mRenamer && mViewModel) + { + arrange( NULL, NULL ); + } } void LLFolderView::draw() @@ -729,7 +725,7 @@ void LLFolderView::draw() void LLFolderView::finishRenamingItem( void ) { - if (!mRenamer) + if(!mRenamer || !mViewModel) { return; } @@ -758,12 +754,33 @@ void LLFolderView::closeRenamer( void ) } } +void LLFolderView::cancelRenaming( void ) +{ + mRenamerTopLostSignalConnection.disconnect(); + + if (mRenamer) + { + mRenamer->setCommitOnFocusLost(false); + if (LLUI::instanceExists()) + { + LLUI::getInstance()->removePopup(mRenamer); + } + if (gFocusMgr.childHasKeyboardFocus(mRenamer)) + { + gFocusMgr.releaseFocusIfNeeded(mRenamer); + } + mRenamer->setVisible(false); + } + + mRenameItem = NULL; +} + void LLFolderView::removeSelectedItems() { if(getVisible() && getEnabled()) { - // just in case we're removing the renaming item. - mRenameItem = NULL; + // Cancel active rename in case the renaming item is among the selected items + cancelRenaming(); // create a temporary structure which we will use to remove // items, since the removal will futz with internal data @@ -1087,6 +1104,7 @@ void LLFolderView::startRenamingSelectedItem( void ) mRenamer->setText(item->getName()); mRenamer->selectAll(); mRenamer->setVisible( true ); + mRenamer->setCommitOnFocusLost( true ); // set focus will fail unless item is visible mRenamer->setFocus( true ); if (!mRenamerTopLostSignalConnection.connected()) @@ -1626,11 +1644,7 @@ bool LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, void LLFolderView::deleteAllChildren() { - mRenamerTopLostSignalConnection.disconnect(); - if (mRenamer) - { - LLUI::getInstance()->removePopup(mRenamer); - } + cancelRenaming(); if (mPopupMenuHandle.get()) { mPopupMenuHandle.get()->die(); diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 368a86ea84..2224ea6e42 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -196,8 +196,11 @@ public: LLFolderViewItem* getNextUnselectedItem(); - // Public rename functionality - can only start the process + // Public rename functionality void startRenamingSelectedItem( void ); + void cancelRenaming( void ); + LLFolderViewItem* getRenameItem() const { return mRenameItem; } + bool isRenaming() const { return mRenameItem != NULL; } // LLView functionality ///*virtual*/ bool handleKey( KEY key, MASK mask, bool called_from_parent ); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index c8ef421677..dea95de955 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -565,7 +565,15 @@ bool LLFolderViewItem::isRemovable() void LLFolderViewItem::destroyView() { - getRoot()->removeFromSelectionList(this); + LLFolderView* root = getRoot(); + if (root) + { + root->removeFromSelectionList(this); + if (root->getRenameItem() == this) + { + root->cancelRenaming(); + } + } if (mParentFolder) { @@ -1822,6 +1830,8 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item, bool deparent_mode { if (item->isSelected()) getRoot()->clearSelection(); + if (getRoot() && getRoot()->getRenameItem() == item) + getRoot()->cancelRenaming(); items_t::iterator it = std::find(mItems.begin(), mItems.end(), item); if(it == mItems.end()) { diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 5f5c8302fe..33231e8405 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1349,6 +1349,14 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par // Destroys the object LLPanelObjectInventory::~LLPanelObjectInventory() { + if (mFolders) + { + mFolders->cancelRenaming(); + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + } if (!gIdleCallbacks.deleteFunction(idle, this)) { LL_WARNS() << "LLPanelObjectInventory::~LLPanelObjectInventory() failed to delete callback" << LL_ENDL; @@ -1398,6 +1406,15 @@ void LLPanelObjectInventory::clearContents() clearItemIDs(); + if (mFolders) + { + mFolders->cancelRenaming(); + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + } + if( mScroller ) { // removes mFolders @@ -1780,6 +1797,14 @@ void LLPanelObjectInventory::draw() void LLPanelObjectInventory::deleteAllChildren() { + if (mFolders) + { + mFolders->cancelRenaming(); + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + } mScroller = NULL; mFolders = NULL; LLView::deleteAllChildren(); -- cgit v1.3