summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2021-01-06 00:45:07 +0200
committerAndrey Kleshchev <andreykproductengine@lindenlab.com>2021-01-06 01:33:26 +0200
commitf86014ef151c7af64de4a08dc4c320e1743fb34b (patch)
tree96047a3d76efa4ffaa92d6f9d398c4e398b9663b /indra/newview
parentdb161b6f85a266ee9d883e3180874de898ccda0e (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/newview')
-rw-r--r--indra/newview/llconversationmodel.cpp14
-rw-r--r--indra/newview/llconversationmodel.h1
-rw-r--r--indra/newview/llconversationview.cpp51
-rw-r--r--indra/newview/llconversationview.h2
-rw-r--r--indra/newview/llfloaterimcontainer.cpp2
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp3
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);
}