From 0bf11e45ea34a21b980c36c99be476613552d560 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 22 Oct 2020 22:07:00 +0300
Subject: [PATCH] SL-14150 Handle more cases of corrupted cache

---
 indra/llrender/llimagegl.cpp      |  4 ++--
 indra/llrender/llimagegl.h        |  3 ++-
 indra/newview/lltexturecache.cpp  |  9 ++++++---
 indra/newview/llviewertexture.cpp | 20 ++++++++++++++++++++
 4 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index c85b9a890aa..0151d20128e 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1387,8 +1387,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	}
 
 	if (mHasExplicitFormat && 
-		(mFormatPrimary == GL_RGBA && mComponents < 4) ||
-		(mFormatPrimary == GL_RGB  && mComponents < 3))
+		((mFormatPrimary == GL_RGBA && mComponents < 4) ||
+		 (mFormatPrimary == GL_RGB  && mComponents < 3)))
 
 	{
 		LL_WARNS()  << "Incorrect format: " << std::hex << mFormatPrimary << " components: " << (U32)mComponents <<  LL_ENDL;		
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 4f3d7eed0a4..472af75d9e6 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -133,6 +133,7 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 	S32  getMipBytes(S32 discard_level = -1) const;
 	BOOL getBoundRecently() const;
 	BOOL isJustBound() const;
+	BOOL getHasEplixitFormat() const { return mHasExplicitFormat; }
 	LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
 	LLGLenum getFormatType() const { return mFormatType; }
 
@@ -197,7 +198,7 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
 	U16 mPickMaskWidth;
 	U16 mPickMaskHeight;
 	S8 mUseMipMaps;
-	S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents)
+	BOOL mHasExplicitFormat; // If false (default), GL format is f(mComponents)
 	S8 mAutoGenMips;
 
 	BOOL mIsMask;
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 2e52414d719..649a9946486 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -52,7 +52,8 @@ const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;//1024;
 const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
 const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
 const S32 TEXTURE_FAST_CACHE_ENTRY_OVERHEAD = sizeof(S32) * 4; //w, h, c, level
-const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = 16 * 16 * 4 + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD;
+const S32 TEXTURE_FAST_CACHE_DATA_SIZE = 16 * 16 * 4;
+const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = TEXTURE_FAST_CACHE_DATA_SIZE + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD;
 const F32 TEXTURE_LAZY_PURGE_TIME_LIMIT = .004f; // 4ms. Would be better to autoadjust, but there is a major cache rework in progress.
 
 class LLTextureCacheWorker : public LLWorkerClass
@@ -2065,7 +2066,9 @@ LLPointer<LLImageRaw> LLTextureCache::readFromFastCache(const LLUUID& id, S32& d
 		}
 		
 		S32 image_size = head[0] * head[1] * head[2];
-		if(!image_size) //invalid
+        if(image_size <= 0
+           || image_size > TEXTURE_FAST_CACHE_DATA_SIZE
+           || head[3] < 0) //invalid
 		{
 			closeFastCache();
 			return NULL;
@@ -2144,7 +2147,7 @@ bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer<LLImage
 
 	S32 i = 0 ;
 	
-	while(((w >> i) * (h >> i) * c) > TEXTURE_FAST_CACHE_ENTRY_SIZE - TEXTURE_FAST_CACHE_ENTRY_OVERHEAD)
+	while(((w >> i) * (h >> i) * c) > TEXTURE_FAST_CACHE_DATA_SIZE)
 	{
 		++i ;
 	}
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a2cec9a6133..b64e576ad7b 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1541,6 +1541,26 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 		return FALSE;
 	}
 
+    if (mGLTexturep->getHasEplixitFormat())
+    {
+        LLGLenum format = mGLTexturep->getPrimaryFormat();
+        S8 components = mRawImage->getComponents();
+        if ((format == GL_RGBA && components < 4)
+            || (format == GL_RGB && components < 3))
+        {
+            LL_WARNS() << "Can't create a texture " << mID << ": invalid image format " << std::hex << format << " vs components " << (U32)components << LL_ENDL;
+            // Was expecting specific format but raw texture has insufficient components for
+            // such format, using such texture will result in crash or will display wrongly
+            // if we change format. Texture might be corrupted server side, so just set as
+            // missing and clear cashed texture (do not cause reload loop, will retry&recover
+            // during new session)
+            setIsMissingAsset();
+            destroyRawImage();
+            LLAppViewer::getTextureCache()->removeFromCache(mID);
+            return FALSE;
+        }
+    }
+
 	res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
 
 	notifyAboutCreatingTexture();
-- 
GitLab