diff options
| author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2021-01-06 00:45:07 +0200 | 
|---|---|---|
| committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2021-01-06 01:33:26 +0200 | 
| commit | f86014ef151c7af64de4a08dc4c320e1743fb34b (patch) | |
| tree | 96047a3d76efa4ffaa92d6f9d398c4e398b9663b /indra | |
| parent | db161b6f85a266ee9d883e3180874de898ccda0e (diff) | |
SL-14270 Crash on participant's updateName
Session was deleted before viewer had a chance to create view for listener, so listener ended up not deleted and avaiting an uptade, then tryed to call for deleted session.
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/llconversationmodel.cpp | 14 | ||||
| -rw-r--r-- | indra/newview/llconversationmodel.h | 1 | ||||
| -rw-r--r-- | indra/newview/llconversationview.cpp | 51 | ||||
| -rw-r--r-- | indra/newview/llconversationview.h | 2 | ||||
| -rw-r--r-- | indra/newview/llfloaterimcontainer.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llfloaterimsessiontab.cpp | 3 | 
6 files changed, 71 insertions, 2 deletions
| diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 8293dc6922..fbdf08d8aa 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -349,6 +349,20 @@ void LLConversationItemSession::clearParticipants()  	mNeedsRefresh = true;  } + +void LLConversationItemSession::deleteParticipantModels() +{ +    // Make sure that no views exist before use and that view-owned items were removed! +    // +    // Normally we are not supposed to delete models directly, they should be +    // owned by views and this action will result in crashes, but LLParticipantList +    // creates models separately from views (it probably shouldn't) and then those +    // models wait for idle cycles to be assigned to view. +    // this code is meant to delete 'waiting' models  +    std::for_each(mChildren.begin(), mChildren.end(), DeletePointer()); +    mChildren.clear(); +} +  LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id)  {  	// This is *not* a general tree parsing algorithm. It assumes that a session contains only  diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 30c7481864..e30bfbb759 100644 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -165,6 +165,7 @@ public:  	void removeParticipant(LLConversationItemParticipant* participant);  	void removeParticipant(const LLUUID& participant_id);  	void clearParticipants(); +	void deleteParticipantModels(); // do not use while there are existing participant views  	LLConversationItemParticipant* findParticipant(const LLUUID& participant_id);  	void setParticipantIsMuted(const LLUUID& participant_id, bool is_muted); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 25971a7d52..71346b4b43 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -103,6 +103,57 @@ LLConversationViewSession::~LLConversationViewSession()  	mFlashTimer->unset();  } +void LLConversationViewSession::destroyView() +{ +    // Chat can create and parent models(listeners) to session's model before creating +    // coresponding views, such participant's models normally will wait for idle cycles +    // but since we are deleting session and won't be processing any more events, make +    // sure unowned models are removed as well. +    // Might be good idea to just have an LLPointer list somewhere in LLConversationItemSession + +    LLConversationItemSession* vmi = dynamic_cast<LLConversationItemSession*>(getViewModelItem()); + +    // CONV_SESSION_1_ON_1 stores participants as two models that belong to views independent +    // from session (nasty! These views are widgets in LLFloaterIMSessionTab, see buildConversationViewParticipant) +    if (vmi && vmi->getType() != LLConversationItem::CONV_SESSION_1_ON_1) +    { +        // Destroy existing views +        while (!mItems.empty()) +        { +            LLFolderViewItem *itemp = mItems.back(); +            mItems.pop_back(); + +            LLFolderViewModelItem* item_vmi = itemp->getViewModelItem(); +            if (item_vmi) // supposed to exist +            { +                // unparent to remove from child list +                vmi->removeChild(item_vmi); +            } +            itemp->destroyView(); +        } + +        // Not needed in scope of sessions, but just in case +        while (!mFolders.empty()) +        { +            LLFolderViewFolder *folderp = mFolders.back(); +            mFolders.pop_back(); + +            LLFolderViewModelItem* folder_vmi = folderp->getViewModelItem(); +            if (folder_vmi) +            { +                vmi->removeChild(folder_vmi); +            } +            folderp->destroyView(); +        } + +        // Now everything that is left in model(listener) is unowned, +        // it is safe to remove +        vmi->deleteParticipantModels(); +    } + +    LLFolderViewFolder::destroyView(); +} +  void LLConversationViewSession::setFlashState(bool flash_state)  {  	if (flash_state && !mFlashStateOn) diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 9762d56d57..0932d24dfe 100644 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -67,6 +67,8 @@ protected:  public:  	virtual ~LLConversationViewSession(); +	/*virtual*/ void destroyView(); +  	/*virtual*/ BOOL postBuild();  	/*virtual*/ void draw();  	/*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 61b0fda18f..86c79791b8 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1822,6 +1822,8 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c  		{  			new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE);  		} + +		// Will destroy views and delete models that are not assigned to any views  		widget->destroyView();  	} diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index fd3f8b21ce..e7f428c06a 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -534,8 +534,7 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part  	LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);  	if (widget)  	{ -		mConversationsRoot->extractItem(widget); -		delete widget; +		widget->destroyView();  	}  	mConversationsWidgets.erase(participant_id);  } | 
