From f5a7fba76a24a96f906abcbd928f37e4eabfa76c Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 12 Apr 2024 02:03:49 +0300
Subject: viewer-private#226 Unhandled PngError throws application into a loop

png_read_info triggered a PngError, LLAppViewer::frame() handled it
instead of LLPngWrapper::readPng, and since status didn't
change viewer tried to decode image again and again and again.
---
 indra/newview/llfloaterimagepreview.cpp |  96 +++++++++++++------------
 indra/newview/llviewertexturelist.cpp   | 122 +++++++++++++++++---------------
 indra/newview/llviewertexturelist.h     |   2 +-
 3 files changed, 118 insertions(+), 102 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index ba0f97e2e1..6da1481c7e 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -332,54 +332,62 @@ void LLFloaterImagePreview::draw()
 //-----------------------------------------------------------------------------
 bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
 {
-	std::string exten = gDirUtilp->getExtension(src_filename);
-	U32 codec = LLImageBase::getCodecFromExtension(exten);
+    try
+    {
+        std::string exten = gDirUtilp->getExtension(src_filename);
+        U32 codec = LLImageBase::getCodecFromExtension(exten);
 
-	LLImageDimensionsInfo image_info;
-	if (!image_info.load(src_filename,codec))
-	{
-		mImageLoadError = image_info.getLastError();
-		return false;
-	}
+        LLImageDimensionsInfo image_info;
+        if (!image_info.load(src_filename, codec))
+        {
+            mImageLoadError = image_info.getLastError();
+            return false;
+        }
 
-	S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
-	S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
+        S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
+        S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
 
-	if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
-	{
-		LLStringUtil::format_map_t args;
-		args["WIDTH"] = llformat("%d", max_width);
-		args["HEIGHT"] = llformat("%d", max_height);
+        if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
+        {
+            LLStringUtil::format_map_t args;
+            args["WIDTH"] = llformat("%d", max_width);
+            args["HEIGHT"] = llformat("%d", max_height);
 
-		mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
-		return false;
-	}
-	
-	// Load the image
-	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
-	if (image.isNull())
-	{
-		return false;
-	}
-	if (!image->load(src_filename))
-	{
-		return false;
-	}
-	// Decompress or expand it in a raw image structure
-	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-	if (!image->decode(raw_image, 0.0f))
-	{
-		return false;
-	}
-	// Check the image constraints
-	if ((image->getComponents() != 3) && (image->getComponents() != 4))
-	{
-		image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
-		return false;
-	}
-	
-	raw_image->biasedScaleToPowerOfTwo(1024);
-	mRawImagep = raw_image;
+            mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
+            return false;
+        }
+
+        // Load the image
+        LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
+        if (image.isNull())
+        {
+            return false;
+        }
+        if (!image->load(src_filename))
+        {
+            return false;
+        }
+        // Decompress or expand it in a raw image structure
+        LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+        if (!image->decode(raw_image, 0.0f))
+        {
+            return false;
+        }
+        // Check the image constraints
+        if ((image->getComponents() != 3) && (image->getComponents() != 4))
+        {
+            image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
+            return false;
+        }
+
+        raw_image->biasedScaleToPowerOfTwo(1024);
+        mRawImagep = raw_image;
+    }
+    catch (...)
+    {
+        LOG_UNHANDLED_EXCEPTION("");
+        return false;
+    }
 	
 	return true;
 }
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 971d3c4363..ccfaad2b15 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1297,7 +1297,7 @@ bool LLViewerTextureList::createUploadFile(LLPointer<LLImageRaw> raw_image,
     return true;
 }
 
-BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
+bool LLViewerTextureList::createUploadFile(const std::string& filename,
 										 const std::string& out_filename,
 										 const U8 codec,
 										 const S32 max_image_dimentions,
@@ -1305,64 +1305,72 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,
 										 bool force_square)
 {	
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
-	// Load the image
-	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
-	if (image.isNull())
-	{
-		LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
-		return FALSE;
-	}	
-	if (!image->load(filename))
-	{
-		image->setLastError("Couldn't load the image to be uploaded.");
-		return FALSE;
-	}
-	// Decompress or expand it in a raw image structure
-	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-	if (!image->decode(raw_image, 0.0f))
-	{
-		image->setLastError("Couldn't decode the image to be uploaded.");
-		return FALSE;
-	}
-	// Check the image constraints
-	if ((image->getComponents() != 3) && (image->getComponents() != 4))
-	{
-		image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
-		return FALSE;
-	}
-    if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
+    try
     {
-        std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
-            min_image_dimentions,
-            min_image_dimentions,
-            image->getWidth(),
-            image->getHeight());
-        image->setLastError(reason);
-        return FALSE;
+        // Load the image
+        LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
+        if (image.isNull())
+        {
+            LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
+            return false;
+        }
+        if (!image->load(filename))
+        {
+            image->setLastError("Couldn't load the image to be uploaded.");
+            return false;
+        }
+        // Decompress or expand it in a raw image structure
+        LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+        if (!image->decode(raw_image, 0.0f))
+        {
+            image->setLastError("Couldn't decode the image to be uploaded.");
+            return false;
+        }
+        // Check the image constraints
+        if ((image->getComponents() != 3) && (image->getComponents() != 4))
+        {
+            image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
+            return false;
+        }
+        if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
+        {
+            std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
+                                          min_image_dimentions,
+                                          min_image_dimentions,
+                                          image->getWidth(),
+                                          image->getHeight());
+            image->setLastError(reason);
+            return false;
+        }
+        // Convert to j2c (JPEG2000) and save the file locally
+        LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
+        if (compressedImage.isNull())
+        {
+            image->setLastError("Couldn't convert the image to jpeg2000.");
+            LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL;
+            return false;
+        }
+        if (!compressedImage->save(out_filename))
+        {
+            image->setLastError("Couldn't create the jpeg2000 image for upload.");
+            LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
+            return false;
+        }
+        // Test to see if the encode and save worked
+        LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
+        if (!integrity_test->loadAndValidate(out_filename))
+        {
+            image->setLastError("The created jpeg2000 image is corrupt.");
+            LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL;
+            return false;
+        }
     }
-	// Convert to j2c (JPEG2000) and save the file locally
-	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
-	if (compressedImage.isNull())
-	{
-		image->setLastError("Couldn't convert the image to jpeg2000.");
-		LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL;
-		return FALSE;
-	}
-	if (!compressedImage->save(out_filename))
-	{
-		image->setLastError("Couldn't create the jpeg2000 image for upload.");
-		LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
-		return FALSE;
-	}
-	// Test to see if the encode and save worked
-	LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
-	if (!integrity_test->loadAndValidate( out_filename ))
-	{
-		image->setLastError("The created jpeg2000 image is corrupt.");
-		LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL;
-		return FALSE;
-	}
-	return TRUE;
+    catch (...)
+    {
+        LOG_UNHANDLED_EXCEPTION("");
+        return false;
+    }
+	return true;
 }
 
 // note: modifies the argument raw_image!!!!
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index 10a2cfa32a..04d3309f86 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -96,7 +96,7 @@ public:
                                  const std::string& out_filename,
                                  const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
                                  const S32 min_image_dimentions = 0);
-    static BOOL createUploadFile(const std::string& filename,
+    static bool createUploadFile(const std::string& filename,
                                  const std::string& out_filename,
                                  const U8 codec,
                                  const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
-- 
cgit v1.2.3