From 1233842012a257b7eb49eab354bb945593c974ed Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 13 Aug 2019 17:22:58 +0300
Subject: SL-11718 Crash in LLRender2D

---
 indra/llrender/llrender2dutils.cpp | 43 ++++++++++++++++++++++++++++++++++++++
 indra/llrender/llrender2dutils.h   | 19 ++++++++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

(limited to 'indra/llrender')

diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp
index 508bccec11..4eb0203245 100644
--- a/indra/llrender/llrender2dutils.cpp
+++ b/indra/llrender/llrender2dutils.cpp
@@ -1570,6 +1570,10 @@ LLRender2D::LLRender2D(LLImageProviderInterface* image_provider)
 {
 	mGLScaleFactor = LLVector2(1.f, 1.f);
 	mImageProvider = image_provider;
+	if(mImageProvider)
+	{
+		mImageProvider->addOnRemovalCallback(resetProvider);
+	}
 }
 
 LLRender2D::~LLRender2D()
@@ -1577,6 +1581,7 @@ LLRender2D::~LLRender2D()
 	if(mImageProvider)
 	{
 		mImageProvider->cleanUp();
+		mImageProvider->deleteOnRemovalCallback(resetProvider);
 	}
 }
 
@@ -1642,3 +1647,41 @@ LLPointer<LLUIImage> LLRender2D::getUIImage(const std::string& name, S32 priorit
 		return NULL;
 }
 
+// static
+void LLRender2D::resetProvider()
+{
+    if (LLRender2D::instanceExists)
+    {
+        LLRender2D::getInstance()->mImageProvider = NULL;
+    }
+}
+
+// class LLImageProviderInterface
+
+LLImageProviderInterface::~LLImageProviderInterface()
+{
+    for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end();)
+    {
+        callback_list_t::iterator curiter = iter++;
+        (*curiter)();
+    }
+}
+
+void LLImageProviderInterface::addOnRemovalCallback(callback_t func)
+{
+    if (!func)
+    {
+        return;
+    }
+    mCallbackList.push_back(func);
+}
+
+void LLImageProviderInterface::deleteOnRemovalCallback(callback_t func)
+{
+    callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), func);
+    if (iter != mCallbackList.end())
+    {
+        mCallbackList.erase(iter);
+    }
+}
+
diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h
index cf408336e6..70ab006fd6 100644
--- a/indra/llrender/llrender2dutils.h
+++ b/indra/llrender/llrender2dutils.h
@@ -139,6 +139,13 @@ public:
 	LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0);
 
 	LLVector2		mGLScaleFactor;
+
+protected:
+	// since LLRender2D has no control of image provider's lifecycle
+	// we need a way to tell LLRender2D that provider died and
+	// LLRender2D needs to be updated.
+	static void resetProvider();
+
 private:
 	LLImageProviderInterface* mImageProvider;
 };
@@ -147,11 +154,21 @@ class LLImageProviderInterface
 {
 protected:
 	LLImageProviderInterface() {};
-	virtual ~LLImageProviderInterface() {};
+	virtual ~LLImageProviderInterface();
 public:
 	virtual LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) = 0;
 	virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) = 0;
 	virtual void cleanUp() = 0;
+
+	// to notify holders when pointer gets deleted
+	typedef void(*callback_t)();
+	void addOnRemovalCallback(callback_t func);
+	void deleteOnRemovalCallback(callback_t func);
+
+private:
+
+	typedef std::list< callback_t >	callback_list_t;
+	callback_list_t mCallbackList;
 };
 
 
-- 
cgit v1.2.3