fix off-by-one in avifGetExifTiffHeaderOffset scan bound (#3400)
diff --git a/src/exif.c b/src/exif.c
index dc89060..42c3de8 100644
--- a/src/exif.c
+++ b/src/exif.c
@@ -11,7 +11,7 @@
     const uint8_t tiffHeaderBE[4] = { 'M', 'M', 0, 42 };
     const uint8_t tiffHeaderLE[4] = { 'I', 'I', 42, 0 };
     exifSize = AVIF_MIN(exifSize, UINT32_MAX);
-    for (*offset = 0; *offset + 4 < exifSize; ++*offset) {
+    for (*offset = 0; *offset + 4 <= exifSize; ++*offset) {
         if (!memcmp(&exif[*offset], tiffHeaderBE, 4) || !memcmp(&exif[*offset], tiffHeaderLE, 4)) {
             return AVIF_RESULT_OK;
         }
diff --git a/tests/gtest/avifmetadatatest.cc b/tests/gtest/avifmetadatatest.cc
index 7fc531b..3808e12 100644
--- a/tests/gtest/avifmetadatatest.cc
+++ b/tests/gtest/avifmetadatatest.cc
@@ -409,6 +409,23 @@
             AVIF_RESULT_OK);
 }
 
+// The TIFF header may be located in the last four bytes of the payload.
+// avifGetExifTiffHeaderOffset() must still find it there.
+TEST(MetadataTest, ExifTiffHeaderOffsetAtEnd) {
+  const uint8_t kLittleEndian[] = {0x00, 0x00, 'I', 'I', 42, 0};
+  size_t offset;
+  ASSERT_EQ(avifGetExifTiffHeaderOffset(kLittleEndian, sizeof(kLittleEndian),
+                                        &offset),
+            AVIF_RESULT_OK);
+  EXPECT_EQ(offset, 2u);
+
+  const uint8_t kBigEndian[] = {0x00, 'M', 'M', 0, 42};
+  ASSERT_EQ(
+      avifGetExifTiffHeaderOffset(kBigEndian, sizeof(kBigEndian), &offset),
+      AVIF_RESULT_OK);
+  EXPECT_EQ(offset, 1u);
+}
+
 //------------------------------------------------------------------------------
 
 TEST(MetadataTest, ExtendedXMP) {