Do not store item pointers until all items are created

Manual cherry-pick of PR #1757 into the chromium-m120 branch.
diff --git a/src/read.c b/src/read.c
index 73410a3..3cbc021 100644
--- a/src/read.c
+++ b/src/read.c
@@ -781,6 +781,8 @@
     avifFree(meta);
 }
 
+// CAUTION: This function could potentially resize the meta->items array thereby invalidating all existing pointers that are being
+// stored locally. So if this function is being called, exercise caution in the caller to not use invalid pointers.
 static avifDecoderItem * avifMetaFindItem(avifMeta * meta, uint32_t itemID)
 {
     if (itemID == 0) {
@@ -1909,11 +1911,12 @@
 // isItemInInput must be false if the item is a made-up structure
 // (and thus not part of the parseable input bitstream).
 static avifResult avifDecoderItemReadAndParse(const avifDecoder * decoder,
-                                              avifDecoderItem * item,
+                                              int itemIndex,
                                               avifBool isItemInInput,
                                               avifImageGrid * grid,
                                               avifCodecType * codecType)
 {
+    avifDecoderItem * item = &decoder->data->meta->items.item[itemIndex];
     if (!memcmp(item->type, "grid", 4)) {
         if (isItemInInput) {
             avifROData readData;
@@ -4154,8 +4157,8 @@
            (avifGetCodecType(item->type) == AVIF_CODEC_TYPE_UNKNOWN && memcmp(item->type, "grid", 4)) || item->thumbnailForID != 0;
 }
 
-// Returns the primary color item if found, or NULL.
-static avifDecoderItem * avifMetaFindColorItem(avifMeta * meta)
+// Returns the index of the primary color item if found, or -1.
+static int avifMetaFindColorItem(avifMeta * meta)
 {
     for (uint32_t itemIndex = 0; itemIndex < meta->items.count; ++itemIndex) {
         avifDecoderItem * item = &meta->items.item[itemIndex];
@@ -4163,10 +4166,10 @@
             continue;
         }
         if (item->id == meta->primaryItemID) {
-            return item;
+            return itemIndex;
         }
     }
-    return NULL;
+    return -1;
 }
 
 // Returns AVIF_TRUE if item is an alpha auxiliary item of the parent color
@@ -4179,39 +4182,40 @@
     return auxCProp && isAlphaURN(auxCProp->u.auxC.auxType);
 }
 
-// Finds the alpha item whose parent item is colorItem and sets it in the alphaItem output parameter. Returns AVIF_RESULT_OK on
-// success. Note that *alphaItem can be NULL even if the return value is AVIF_RESULT_OK. If the colorItem is a grid and the alpha
-// item is represented as a set of auxl items to each color tile, then a fake item will be created and *isAlphaItemInInput will be
-// set to AVIF_FALSE. In this case, the alpha item merely exists to hold the locations of the alpha tile items. The data of this
-// item need not be read and the pixi property cannot be validated. Otherwise, *isAlphaItemInInput will be set to AVIF_TRUE when
-// *alphaItem is not NULL.
+// Finds the alpha item whose parent item is the color item and sets its index in the alphaItemIndex output parameter. Returns
+// AVIF_RESULT_OK on success. Note that *alphaItemIndex can be -1 even if the return value is AVIF_RESULT_OK. If the color item is
+// a grid and the alpha item is represented as a set of auxl items to each color tile, then a fake item will be created and
+// *isAlphaItemInInput will be set to AVIF_FALSE. In this case, the alpha item merely exists to hold the locations of the alpha
+// tile items. The data of this item need not be read and the pixi property cannot be validated. Otherwise, *isAlphaItemInInput
+// will be set to AVIF_TRUE when *alphaItemIndex is not -1.
 static avifResult avifMetaFindAlphaItem(avifMeta * meta,
-                                        const avifDecoderItem * colorItem,
+                                        int colorItemIndex,
                                         const avifTileInfo * colorInfo,
-                                        avifDecoderItem ** alphaItem,
+                                        int * alphaItemIndex,
                                         avifTileInfo * alphaInfo,
                                         avifBool * isAlphaItemInInput)
 {
+    const avifDecoderItem * colorItem = &meta->items.item[colorItemIndex];
     for (uint32_t itemIndex = 0; itemIndex < meta->items.count; ++itemIndex) {
         avifDecoderItem * item = &meta->items.item[itemIndex];
         if (avifDecoderItemShouldBeSkipped(item)) {
             continue;
         }
         if (avifDecoderItemIsAlphaAux(item, colorItem->id)) {
-            *alphaItem = item;
+            *alphaItemIndex = itemIndex;
             *isAlphaItemInInput = AVIF_TRUE;
             return AVIF_RESULT_OK;
         }
     }
     if (memcmp(colorItem->type, "grid", 4)) {
-        *alphaItem = NULL;
+        *alphaItemIndex = -1;
         *isAlphaItemInInput = AVIF_FALSE;
         return AVIF_RESULT_OK;
     }
     // If color item is a grid, check if there is an alpha channel which is represented as an auxl item to each color tile item.
     uint32_t colorItemCount = colorInfo->grid.rows * colorInfo->grid.columns;
     if (colorItemCount == 0) {
-        *alphaItem = NULL;
+        *alphaItemIndex = -1;
         *isAlphaItemInInput = AVIF_FALSE;
         return AVIF_RESULT_OK;
     }
@@ -4236,22 +4240,27 @@
     if (alphaItemCount != colorItemCount) {
         // Not all the color items had an alpha auxiliary attached to it. Report this case as an image without alpha channel.
         avifFree(alphaItemIndices);
-        *alphaItem = NULL;
+        *alphaItemIndex = -1;
         *isAlphaItemInInput = AVIF_FALSE;
         return AVIF_RESULT_OK;
     }
-    *alphaItem = avifMetaFindItem(meta, maxItemID + 1); // Create new empty item.
-    if (*alphaItem == NULL) {
+    avifDecoderItem * alphaItem =  avifMetaFindItem(meta, maxItemID + 1); // Create new empty item.
+    if (alphaItem == NULL) {
         avifFree(alphaItemIndices);
+        *alphaItemIndex = -1;
         *isAlphaItemInInput = AVIF_FALSE;
         return AVIF_RESULT_OUT_OF_MEMORY;
     }
-    memcpy((*alphaItem)->type, "grid", 4); // Make it a grid and register alpha items as its tiles.
-    (*alphaItem)->width = colorItem->width;
-    (*alphaItem)->height = colorItem->height;
+    *alphaItemIndex = meta->items.count - 1;
+    // avifMetaFindItem() could invalidate all existing item pointers. So reset the colorItem pointer.
+    colorItem = &meta->items.item[colorItemIndex];
+
+    memcpy(alphaItem->type, "grid", 4); // Make it a grid and register alpha items as its tiles.
+    alphaItem->width = colorItem->width;
+    alphaItem->height = colorItem->height;
     for (uint32_t i = 0; i < alphaItemCount; ++i) {
         avifDecoderItem * item = &meta->items.item[alphaItemIndices[i]];
-        item->dimgForID = (*alphaItem)->id;
+        item->dimgForID = alphaItem->id;
     }
     avifFree(alphaItemIndices);
     *isAlphaItemInInput = AVIF_FALSE;
@@ -4310,43 +4319,52 @@
     return AVIF_RESULT_OK;
 }
 
-// Finds a 'tmap' (tone mapped image item) box associated with the given 'colorItem',
-// then finds the associated gain map image.
-// If found, fills 'toneMappedImageItem', 'gainMapItem' and  'gainMapCodecType'.
-// Otherwise, sets 'toneMappedImageItem' and 'gainMapItem' to NULL.
+// Finds a 'tmap' (tone mapped image item) box associated with the given color item at index 'colorItemIndex', then finds the
+// associated gain map image.
+// If found, fills 'toneMappedImageItem', 'gainMapItemIndex' and  'gainMapCodecType'.
+// Otherwise, sets 'toneMappedImageItem' to NULL and 'gainMapItemIndex' to -1.
 // Returns AVIF_RESULT_OK if no errors were encountered (whether or not a gain map was found).
 // Assumes that there is a single tmap item, and not, e.g., a grid of tmap items.
 static avifResult avifDecoderFindGainMapItem(const avifDecoder * decoder,
-                                             const avifDecoderItem * colorItem,
+                                             int colorItemIndex,
                                              avifDecoderItem ** toneMappedImageItem,
-                                             avifDecoderItem ** gainMapItem,
+                                             int * gainMapItemIndex,
                                              avifCodecType * gainMapCodecType)
 {
     *toneMappedImageItem = NULL;
-    *gainMapItem = NULL;
+    *gainMapItemIndex = -1;
     *gainMapCodecType = AVIF_CODEC_TYPE_UNKNOWN;
 
     avifDecoderData * data = decoder->data;
 
     uint32_t gainMapItemID;
     avifDecoderItem * toneMappedImageItemTmp;
-    AVIF_CHECKRES(avifDecoderDataFindToneMappedImageItem(data, colorItem, &toneMappedImageItemTmp, &gainMapItemID));
+    AVIF_CHECKRES(
+        avifDecoderDataFindToneMappedImageItem(data, &data->meta->items.item[colorItemIndex], &toneMappedImageItemTmp, &gainMapItemID));
     if (!toneMappedImageItemTmp) {
         return AVIF_RESULT_OK;
     }
 
-    avifDecoderItem * gainMapItemTmp = avifMetaFindItem(data->meta, gainMapItemID);
-    if (!gainMapItemTmp) {
+    avifDecoderItem * gainMapItem =  avifMetaFindItem(data->meta, gainMapItemID);
+    if (!gainMapItem) {
         avifDiagnosticsPrintf(data->diag, "Box[tmap] gain map item ID %d not found", gainMapItemID);
         return AVIF_RESULT_INVALID_TONE_MAPPED_IMAGE;
     }
-    if (avifDecoderItemShouldBeSkipped(gainMapItemTmp)) {
+    if (avifDecoderItemShouldBeSkipped(gainMapItem)) {
         avifDiagnosticsPrintf(data->diag, "Box[tmap] gain map item %d is not a supported image type", gainMapItemID);
         return AVIF_RESULT_INVALID_TONE_MAPPED_IMAGE;
     }
+    int gainMapItemIndexTmp = -1;
+    for (uint32_t itemIndex = 0; itemIndex < data->meta->items.count; ++itemIndex) {
+        if (gainMapItem->id == data->meta->items.item[itemIndex].id) {
+            gainMapItemIndexTmp = itemIndex;
+            break;
+        }
+    }
+    assert(gainMapItemIndexTmp >= 0);
 
     AVIF_CHECKRES(avifDecoderItemReadAndParse(decoder,
-                                              gainMapItemTmp,
+                                              gainMapItemIndexTmp,
                                               /*isItemInInput=*/AVIF_TRUE,
                                               &data->tileInfos[AVIF_ITEM_GAIN_MAP].grid,
                                               gainMapCodecType));
@@ -4355,8 +4373,8 @@
         decoder->image->gainMap.image = avifImageCreateEmpty();
 
         // Look for a colr nclx box. Other colr box types (e.g. ICC) are not supported.
-        for (uint32_t propertyIndex = 0; propertyIndex < gainMapItemTmp->properties.count; ++propertyIndex) {
-            avifProperty * prop = &gainMapItemTmp->properties.prop[propertyIndex];
+        for (uint32_t propertyIndex = 0; propertyIndex < gainMapItem->properties.count; ++propertyIndex) {
+            avifProperty * prop = &gainMapItem->properties.prop[propertyIndex];
             if (!memcmp(prop->type, "colr", 4) && prop->u.colr.hasNCLX) {
                 decoder->image->gainMap.image->colorPrimaries = prop->u.colr.colorPrimaries;
                 decoder->image->gainMap.image->transferCharacteristics = prop->u.colr.transferCharacteristics;
@@ -4381,7 +4399,7 @@
 
     // Only set the output parameters after everything has been validated.
     *toneMappedImageItem = toneMappedImageItemTmp;
-    *gainMapItem = gainMapItemTmp;
+    *gainMapItemIndex = gainMapItemIndexTmp;
     return AVIF_RESULT_OK;
 }
 #endif // AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP
@@ -4597,38 +4615,38 @@
         }
 
         // Main item of each group category (top-level item such as grid or single tile), if any.
-        avifDecoderItem * mainItems[AVIF_ITEM_CATEGORY_COUNT];
+        int mainItemIndices[AVIF_ITEM_CATEGORY_COUNT];
         avifCodecType codecType[AVIF_ITEM_CATEGORY_COUNT];
         for (int c = 0; c < AVIF_ITEM_CATEGORY_COUNT; ++c) {
-            mainItems[c] = NULL;
+            mainItemIndices[c] = -1;
             codecType[c] = AVIF_CODEC_TYPE_UNKNOWN;
         }
 
         // Mandatory primary color item
-        mainItems[AVIF_ITEM_COLOR] = avifMetaFindColorItem(data->meta);
-        if (!mainItems[AVIF_ITEM_COLOR]) {
+        mainItemIndices[AVIF_ITEM_COLOR] = avifMetaFindColorItem(data->meta);
+        if (mainItemIndices[AVIF_ITEM_COLOR] == -1) {
             avifDiagnosticsPrintf(&decoder->diag, "Primary item not found");
             return AVIF_RESULT_MISSING_IMAGE_ITEM;
         }
         AVIF_CHECKRES(avifDecoderItemReadAndParse(decoder,
-                                                  mainItems[AVIF_ITEM_COLOR],
+                                                  mainItemIndices[AVIF_ITEM_COLOR],
                                                   /*isItemInInput=*/AVIF_TRUE,
                                                   &data->tileInfos[AVIF_ITEM_COLOR].grid,
                                                   &codecType[AVIF_ITEM_COLOR]));
-        colorProperties = &mainItems[AVIF_ITEM_COLOR]->properties;
+        colorProperties = &data->meta->items.item[mainItemIndices[AVIF_ITEM_COLOR]].properties;
         colorCodecType = codecType[AVIF_ITEM_COLOR];
 
         // Optional alpha auxiliary item
         avifBool isAlphaItemInInput;
         AVIF_CHECKRES(avifMetaFindAlphaItem(data->meta,
-                                            mainItems[AVIF_ITEM_COLOR],
+                                            mainItemIndices[AVIF_ITEM_COLOR],
                                             &data->tileInfos[AVIF_ITEM_COLOR],
-                                            &mainItems[AVIF_ITEM_ALPHA],
+                                            &mainItemIndices[AVIF_ITEM_ALPHA],
                                             &data->tileInfos[AVIF_ITEM_ALPHA],
                                             &isAlphaItemInInput));
-        if (mainItems[AVIF_ITEM_ALPHA]) {
+        if (mainItemIndices[AVIF_ITEM_ALPHA] != -1) {
             AVIF_CHECKRES(avifDecoderItemReadAndParse(decoder,
-                                                      mainItems[AVIF_ITEM_ALPHA],
+                                                      mainItemIndices[AVIF_ITEM_ALPHA],
                                                       isAlphaItemInInput,
                                                       &data->tileInfos[AVIF_ITEM_ALPHA].grid,
                                                       &codecType[AVIF_ITEM_ALPHA]));
@@ -4637,9 +4655,9 @@
 #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
         avifDecoderItem * toneMappedImageItem;
         const avifResult findGainMapResult = avifDecoderFindGainMapItem(decoder,
-                                                                        mainItems[AVIF_ITEM_COLOR],
+                                                                        mainItemIndices[AVIF_ITEM_COLOR],
                                                                         &toneMappedImageItem,
-                                                                        &mainItems[AVIF_ITEM_GAIN_MAP],
+                                                                        &mainItemIndices[AVIF_ITEM_GAIN_MAP],
                                                                         &codecType[AVIF_ITEM_GAIN_MAP]);
         if (!decoder->enableDecodingGainMap) {
             // When ignoring the gain map, we still report whether one is present or not,
@@ -4650,9 +4668,9 @@
                 // Clear diagnostic message.
                 avifDiagnosticsClearError(data->diag);
             }
-            decoder->gainMapPresent = (mainItems[AVIF_ITEM_GAIN_MAP] != NULL);
+            decoder->gainMapPresent = (mainItemIndices[AVIF_ITEM_GAIN_MAP] != -1);
             // We also ignore the actual item and don't decode it.
-            mainItems[AVIF_ITEM_GAIN_MAP] = NULL;
+            mainItemIndices[AVIF_ITEM_GAIN_MAP] = -1;
         } else {
             AVIF_CHECKRES(findGainMapResult);
         }
@@ -4666,6 +4684,14 @@
         }
 #endif // AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP
 
+        // When searching for alpha and gainmap items, it is possible that the data->meta->items array is re-sized in calls to
+        // avifMetaFindItem. So it is not safe to store pointers into the data->meta->items array until all the items are
+        // either found or created. From this point onwards, we do not create any more items, so it is safe to store the pointers.
+        avifDecoderItem * mainItems[AVIF_ITEM_CATEGORY_COUNT];
+        for (int c = 0; c < AVIF_ITEM_CATEGORY_COUNT; ++c) {
+            mainItems[c] = (mainItemIndices[c] == -1) ? NULL : &data->meta->items.item[mainItemIndices[c]];
+        }
+
         // Find Exif and/or XMP metadata, if any
         AVIF_CHECKRES(avifDecoderFindMetadata(decoder, data->meta, decoder->image, mainItems[AVIF_ITEM_COLOR]->id));