Fix memory leak of altICC if avifDecoderFindGainMapItem returns early. (#3127)

Make sure none of the inputs variables are modified until the very end.

Fixes b/495087335
diff --git a/src/read.c b/src/read.c
index 430e375..a768ed9 100644
--- a/src/read.c
+++ b/src/read.c
@@ -5792,12 +5792,12 @@
     // Allocate avifGainMap on the stack instead of using avifGainMapCreate() to simplify error handling.
     avifGainMap gainMapTmp;
     avifGainMapSetDefaults(&gainMapTmp);
-    const avifResult tmapParsingRes = avifParseToneMappedImageBox(&gainMapTmp, tmapData.data, tmapData.size, data->diag);
-    if (tmapParsingRes == AVIF_RESULT_NOT_IMPLEMENTED) {
+    avifResult result = avifParseToneMappedImageBox(&gainMapTmp, tmapData.data, tmapData.size, data->diag);
+    if (result == AVIF_RESULT_NOT_IMPLEMENTED) {
         // Unsupported gain map version. Simply ignore the gain map.
         return AVIF_RESULT_OK;
     }
-    AVIF_CHECKRES(tmapParsingRes);
+    AVIF_CHECKRES(result);
 
     avifDecoderItem * gainMapItemTmp;
     AVIF_CHECKRES(avifMetaFindOrCreateItem(data->meta, gainMapItemID, &gainMapItemTmp));
@@ -5805,24 +5805,30 @@
         return AVIF_RESULT_NOT_IMPLEMENTED;
     }
 
-    const avifResult gainMapParsingRes = avifDecoderItemReadAndParse(decoder,
-                                                                     gainMapItemTmp,
-                                                                     /*isItemInInput=*/AVIF_TRUE,
-                                                                     &data->tileInfos[AVIF_ITEM_GAIN_MAP].grid,
-                                                                     gainMapCodecType);
-    if (gainMapParsingRes == AVIF_RESULT_NOT_IMPLEMENTED) {
+    avifCodecType gainMapCodecTypeTmp;
+    result = avifDecoderItemReadAndParse(decoder,
+                                         gainMapItemTmp,
+                                         /*isItemInInput=*/AVIF_TRUE,
+                                         &data->tileInfos[AVIF_ITEM_GAIN_MAP].grid,
+                                         &gainMapCodecTypeTmp);
+    if (result == AVIF_RESULT_NOT_IMPLEMENTED) {
         return AVIF_RESULT_OK;
     }
-    AVIF_CHECKRES(gainMapParsingRes);
+    AVIF_CHECKRES(result);
 
-    AVIF_CHECKRES(avifReadColorProperties(decoder->io,
-                                          &toneMappedImageItemTmp->properties,
-                                          &gainMapTmp.altICC,
-                                          &gainMapTmp.altColorPrimaries,
-                                          &gainMapTmp.altTransferCharacteristics,
-                                          &gainMapTmp.altMatrixCoefficients,
-                                          &gainMapTmp.altYUVRange,
-                                          /*cicpSet=*/NULL));
+    // This may allocate gainMapTmp.altICC which must be freed in case of error.
+    result = avifReadColorProperties(decoder->io,
+                                     &toneMappedImageItemTmp->properties,
+                                     &gainMapTmp.altICC,
+                                     &gainMapTmp.altColorPrimaries,
+                                     &gainMapTmp.altTransferCharacteristics,
+                                     &gainMapTmp.altMatrixCoefficients,
+                                     &gainMapTmp.altYUVRange,
+                                     /*cicpSet=*/NULL);
+    if (result != AVIF_RESULT_OK) {
+        avifRWDataFree(&gainMapTmp.altICC);
+        return result;
+    }
 
     const avifProperty * clliProp = avifPropertyArrayFind(&toneMappedImageItemTmp->properties, "clli");
     if (clliProp) {
@@ -5841,10 +5847,12 @@
         // Every image item shall be associated with one property of this type, prior to the association
         // of all transformative properties.
         avifDiagnosticsPrintf(data->diag, "Box[tmap] missing mandatory ispe property");
+        avifRWDataFree(&gainMapTmp.altICC);
         return AVIF_RESULT_BMFF_PARSE_FAILED;
     }
     if (ispeProp->u.ispe.width != colorItem->width || ispeProp->u.ispe.height != colorItem->height) {
         avifDiagnosticsPrintf(data->diag, "Box[tmap] ispe property width/height does not match base image");
+        avifRWDataFree(&gainMapTmp.altICC);
         return AVIF_RESULT_BMFF_PARSE_FAILED;
     }
 
@@ -5859,6 +5867,7 @@
         // enforced at encoding. Other patterns are rejected at decoding.
         avifDiagnosticsPrintf(data->diag,
                               "Box[tmap] 'pasp', 'clap', 'irot' and 'imir' properties must be associated with base and gain map items instead of 'tmap'");
+        avifRWDataFree(&gainMapTmp.altICC);
         return AVIF_RESULT_INVALID_TONE_MAPPED_IMAGE;
     }
 
@@ -5868,29 +5877,40 @@
     avifRange yuvRange = AVIF_RANGE_FULL;
     avifBool cicpSet = AVIF_FALSE;
     // Look for a colr nclx box. Other colr box types (e.g. ICC) are not supported.
-    AVIF_CHECKRES(
-        avifReadColorNclxProperty(&gainMapItemTmp->properties, &colorPrimaries, &transferCharacteristics, &matrixCoefficients, &yuvRange, &cicpSet));
+    result =
+        avifReadColorNclxProperty(&gainMapItemTmp->properties, &colorPrimaries, &transferCharacteristics, &matrixCoefficients, &yuvRange, &cicpSet);
+    if (result != AVIF_RESULT_OK) {
+        avifRWDataFree(&gainMapTmp.altICC);
+        return result;
+    }
 
     // -- Everything is valid, do memory allocations and fill in output data. --
 
     decoder->image->gainMap = avifGainMapCreate();
-    AVIF_CHECKERR(decoder->image->gainMap, AVIF_RESULT_OUT_OF_MEMORY);
-    *decoder->image->gainMap = gainMapTmp;
+    if (!decoder->image->gainMap) {
+        avifRWDataFree(&gainMapTmp.altICC);
+        return AVIF_RESULT_OUT_OF_MEMORY;
+    }
 
     if (decoder->imageContentToDecode & AVIF_IMAGE_CONTENT_GAIN_MAP) {
-        decoder->image->gainMap->image = avifImageCreateEmpty();
-        avifImage * image = decoder->image->gainMap->image;
-        AVIF_CHECKERR(image, AVIF_RESULT_OUT_OF_MEMORY);
+        avifImage * image = avifImageCreateEmpty();
+        if (!image) {
+            avifRWDataFree(&gainMapTmp.altICC);
+            return AVIF_RESULT_OUT_OF_MEMORY;
+        }
         if (cicpSet) {
             image->colorPrimaries = colorPrimaries;
             image->transferCharacteristics = transferCharacteristics;
             image->matrixCoefficients = matrixCoefficients;
             image->yuvRange = yuvRange;
         }
+        gainMapTmp.image = image;
     }
 
-    // Only set the output pointer after everything has been validated.
+    // Only set the output pointers after everything has been validated.
+    *decoder->image->gainMap = gainMapTmp;
     *gainMapItem = gainMapItemTmp;
+    *gainMapCodecType = gainMapCodecTypeTmp;
     return AVIF_RESULT_OK;
 }