From dce1fae986f4f61f51e7825de903aa58239c28c8 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 23 Nov 2023 23:28:10 +0200
Subject: SL-17076 MacOS crash on clearing ChicletNotificationChannel

Crash appears to happens inside mItems.clear() of the
LLNotificationChannelBase, but there is no apparent reson for it and
stack jumped some steps, so I'm doing cleanup more explicitly to see
if it's indeed there and not a corruption somewhere earlier.
---
 indra/llui/llnotifications.cpp | 14 +++++++++++---
 indra/llui/llnotifications.h   |  8 +++++---
 indra/newview/llchiclet.cpp    |  5 +++++
 indra/newview/llchiclet.h      | 11 +++++++----
 4 files changed, 28 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index d736aa6634..c0a7866926 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1171,6 +1171,14 @@ LLNotificationChannel::LLNotificationChannel(const std::string& name,
 	connectToChannel(parent);
 }
 
+LLNotificationChannel::~LLNotificationChannel()
+{
+    for (LLBoundListener &listener : mListeners)
+    {
+        listener.disconnect();
+    }
+}
+
 bool LLNotificationChannel::isEmpty() const
 {
 	return mItems.empty();
@@ -1213,14 +1221,14 @@ void LLNotificationChannel::connectToChannel( const std::string& channel_name )
 {
 	if (channel_name.empty())
 	{
-		LLNotifications::instance().connectChanged(
-			boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
+        mListeners.push_back(LLNotifications::instance().connectChanged(
+			boost::bind(&LLNotificationChannelBase::updateItem, this, _1)));
 	}
 	else
 	{
 		mParents.push_back(channel_name);
 		LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name);
-		p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
+        mListeners.push_back(p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1)));
 	}
 }
 
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 921398a693..1577038c36 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -835,7 +835,7 @@ public:
 	LLNotificationChannel(const Params& p = Params());
 	LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter);
 
-	virtual ~LLNotificationChannel() {}
+	virtual ~LLNotificationChannel();
 	typedef LLNotificationSet::iterator Iterator;
     
 	std::string getName() const { return mName; }
@@ -845,8 +845,6 @@ public:
 		return boost::iterator_range<parents_iter>(mParents);
 	}
     
-	void connectToChannel(const std::string& channel_name);
-    
     bool isEmpty() const;
     S32 size() const;
     
@@ -856,9 +854,13 @@ public:
 	
 	std::string summarize();
 
+protected:
+    void connectToChannel(const std::string& channel_name);
+
 private:
 	std::string mName;
 	std::vector<std::string> mParents;
+    std::vector<LLBoundListener> mListeners;
 };
 
 // An interface class to provide a clean linker seam to the LLNotifications class.
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index cc4f4536a4..3444f50e52 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -177,6 +177,11 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p)
 	LLFloaterNotificationsTabbed::getInstance()->setSysWellChiclet(this);
 }
 
+LLNotificationChiclet::~LLNotificationChiclet()
+{
+    mNotificationChannel.reset();
+}
+
 void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
 {
 	std::string action = user_data.asString();
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index 58a797218f..1698fa269a 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -531,8 +531,9 @@ public:
 	struct Params : public LLInitParam::Block<Params, LLSysWellChiclet::Params>{};
 		
 protected:
-	struct ChicletNotificationChannel : public LLNotificationChannel
+	class ChicletNotificationChannel : public LLNotificationChannel
 	{
+    public:
 		ChicletNotificationChannel(LLNotificationChiclet* chiclet) 
 			: LLNotificationChannel(LLNotificationChannel::Params().filter(filterNotification).name(chiclet->getSessionId().asString()))
 			, mChiclet(chiclet)
@@ -542,6 +543,7 @@ protected:
 			connectToChannel("Offer");
 			connectToChannel("Notifications");
 		}
+        virtual ~ChicletNotificationChannel() {}
 				
 		static bool filterNotification(LLNotificationPtr notify);
 		// connect counter updaters to the corresponding signals
@@ -553,9 +555,10 @@ protected:
 	};
 				
 	boost::scoped_ptr<ChicletNotificationChannel> mNotificationChannel;
-				
-	LLNotificationChiclet(const Params& p);
-				
+
+    LLNotificationChiclet(const Params& p);
+    ~LLNotificationChiclet();
+
 	/**
 	 * Processes clicks on chiclet menu.
 	 */
-- 
cgit v1.2.3