Upgrade libtiff from 4.6.0 to 4.7.0

Also empty out the entries in third_party/libtiff/METADATA, since 4.7.0
has fixes for all of them.

Change-Id: Ic2de828554cbb785aa59243e31ccbe4f43085339
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/125130
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Tom Sepez <tsepez@google.com>
diff --git a/third_party/libtiff/0000-build-config.patch b/third_party/libtiff/0000-build-config.patch
index c3925b0..4312834 100644
--- a/third_party/libtiff/0000-build-config.patch
+++ b/third_party/libtiff/0000-build-config.patch
@@ -35,7 +35,7 @@
 diff a/third_party/libtiff/tiffconf.h b/third_party/libtiff/tiffconf.h
 --- /dev/null
 +++ b/third_party/libtiff/tiffconf.h
-@@ -0,0 +1,244 @@
+@@ -0,0 +1,240 @@
 +/* libtiff/tiffconf.h.  Generated by configure.  */
 +/*
 +  Configuration defines for installed libtiff.
@@ -211,11 +211,7 @@
 +
 +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
 +   (Intel) */
-+#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_
-+# define HOST_BIGENDIAN 1
-+#else
-+# define HOST_BIGENDIAN 0
-+#endif
++#define HOST_BIGENDIAN 0
 +
 +/* Support CCITT Group 3 & 4 algorithms */
 +#define CCITT_SUPPORT 1
@@ -249,7 +245,7 @@
 +/* #undef ZIP_SUPPORT */
 +
 +/* Support strip chopping (whether or not to convert single-strip uncompressed
-+   images to mutiple strips of ~8Kb to reduce memory usage) */
++   images to multiple strips of ~8Kb to reduce memory usage) */
 +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
 +
 +/* Enable SubIFD tag (330) support */
diff --git a/third_party/libtiff/METADATA b/third_party/libtiff/METADATA
index 6cbd8cf..7b31b74 100644
--- a/third_party/libtiff/METADATA
+++ b/third_party/libtiff/METADATA
@@ -6,18 +6,5 @@
 
 third_party {
   security {
-    # PDFium's copy of libtiff does not ship tools like tiffcrop.
-    mitigated_security_patch: "CVE-2022-48281"
-    mitigated_security_patch: "CVE-2023-1916"
-    mitigated_security_patch: "CVE-2023-3164"
-    mitigated_security_patch: "CVE-2023-25433"
-    mitigated_security_patch: "CVE-2023-25434"
-    mitigated_security_patch: "CVE-2023-25435"
-    mitigated_security_patch: "CVE-2023-26965"
-    mitigated_security_patch: "CVE-2023-40745"
-    mitigated_security_patch: "CVE-2023-41175"
-
-    # There are no callers to TIFFRasterScanlineSize() in PDFium's code base.
-    mitigated_security_patch: "CVE-2023-52355"
   }
 }
diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium
index fc60596..cfe60c6 100644
--- a/third_party/libtiff/README.pdfium
+++ b/third_party/libtiff/README.pdfium
@@ -1,7 +1,7 @@
 Name: LibTIFF
 URL: http://www.simplesystems.org/libtiff/
-Version: 4.6.0
-CPEPrefix: cpe:/a:libtiff:libtiff:4.6.0
+Version: 4.7.0
+CPEPrefix: cpe:/a:libtiff:libtiff:4.7.0
 Security Critical: yes
 Shipped: yes
 License: BSD
diff --git a/third_party/libtiff/tif_aux.c b/third_party/libtiff/tif_aux.c
index 49855bb..e9606a4 100644
--- a/third_party/libtiff/tif_aux.c
+++ b/third_party/libtiff/tif_aux.c
@@ -385,53 +385,6 @@
     return (ok);
 }
 
-struct _Int64Parts
-{
-    int32_t low, high;
-};
-
-typedef union
-{
-    struct _Int64Parts part;
-    int64_t value;
-} _Int64;
-
-float _TIFFUInt64ToFloat(uint64_t ui64)
-{
-    _Int64 i;
-
-    i.value = ui64;
-    if (i.part.high >= 0)
-    {
-        return (float)i.value;
-    }
-    else
-    {
-        long double df;
-        df = (long double)i.value;
-        df += 18446744073709551616.0; /* adding 2**64 */
-        return (float)df;
-    }
-}
-
-double _TIFFUInt64ToDouble(uint64_t ui64)
-{
-    _Int64 i;
-
-    i.value = ui64;
-    if (i.part.high >= 0)
-    {
-        return (double)i.value;
-    }
-    else
-    {
-        long double df;
-        df = (long double)i.value;
-        df += 18446744073709551616.0; /* adding 2**64 */
-        return (double)df;
-    }
-}
-
 float _TIFFClampDoubleToFloat(double val)
 {
     if (val > FLT_MAX)
diff --git a/third_party/libtiff/tif_close.c b/third_party/libtiff/tif_close.c
index 907d7f1..d6bb7f1 100644
--- a/third_party/libtiff/tif_close.c
+++ b/third_party/libtiff/tif_close.c
@@ -110,6 +110,14 @@
         _TIFFfreeExt(tif, tif->tif_fieldscompat);
     }
 
+    if (tif->tif_cur_cumulated_mem_alloc != 0)
+    {
+        TIFFErrorExtR(tif, "TIFFCleanup",
+                      "tif_cur_cumulated_mem_alloc = %" PRIu64 " whereas it "
+                      "should be 0",
+                      (uint64_t)tif->tif_cur_cumulated_mem_alloc);
+    }
+
     _TIFFfreeExt(NULL, tif);
 }
 
diff --git a/third_party/libtiff/tif_color.c b/third_party/libtiff/tif_color.c
index 2d7dcac..a52fdac 100644
--- a/third_party/libtiff/tif_color.c
+++ b/third_party/libtiff/tif_color.c
@@ -89,7 +89,7 @@
 void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
                   uint32_t *r, uint32_t *g, uint32_t *b)
 {
-    int i;
+    size_t i;
     float Yr, Yg, Yb;
     float *matrix = &cielab->display.d_mat[0][0];
 
@@ -109,16 +109,16 @@
     Yb = TIFFmin(Yb, cielab->display.d_YCB);
 
     /* Turn luminosity to colour value. */
-    i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep);
-    i = TIFFmin(cielab->range, i);
+    i = (size_t)((Yr - cielab->display.d_Y0R) / cielab->rstep);
+    i = TIFFmin((size_t)cielab->range, i);
     *r = RINT(cielab->Yr2r[i]);
 
-    i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep);
-    i = TIFFmin(cielab->range, i);
+    i = (size_t)((Yg - cielab->display.d_Y0G) / cielab->gstep);
+    i = TIFFmin((size_t)cielab->range, i);
     *g = RINT(cielab->Yg2g[i]);
 
-    i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep);
-    i = TIFFmin(cielab->range, i);
+    i = (size_t)((Yb - cielab->display.d_Y0B) / cielab->bstep);
+    i = TIFFmin((size_t)cielab->range, i);
     *b = RINT(cielab->Yb2b[i]);
 
     /* Clip output. */
@@ -135,7 +135,7 @@
 int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
                         float *refWhite)
 {
-    int i;
+    size_t i;
     double dfGamma;
 
     cielab->range = CIELABTORGB_TABLE_RANGE;
@@ -146,7 +146,7 @@
     dfGamma = 1.0 / cielab->display.d_gammaR;
     cielab->rstep =
         (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
-    for (i = 0; i <= cielab->range; i++)
+    for (i = 0; i <= (size_t)cielab->range; i++)
     {
         cielab->Yr2r[i] = cielab->display.d_Vrwr *
                           ((float)pow((double)i / cielab->range, dfGamma));
@@ -156,7 +156,7 @@
     dfGamma = 1.0 / cielab->display.d_gammaG;
     cielab->gstep =
         (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
-    for (i = 0; i <= cielab->range; i++)
+    for (i = 0; i <= (size_t)cielab->range; i++)
     {
         cielab->Yg2g[i] = cielab->display.d_Vrwg *
                           ((float)pow((double)i / cielab->range, dfGamma));
@@ -166,7 +166,7 @@
     dfGamma = 1.0 / cielab->display.d_gammaB;
     cielab->bstep =
         (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
-    for (i = 0; i <= cielab->range; i++)
+    for (i = 0; i <= (size_t)cielab->range; i++)
     {
         cielab->Yb2b[i] = cielab->display.d_Vrwb *
                           ((float)pow((double)i / cielab->range, dfGamma));
diff --git a/third_party/libtiff/tif_dir.c b/third_party/libtiff/tif_dir.c
index 85006218..459f969 100644
--- a/third_party/libtiff/tif_dir.c
+++ b/third_party/libtiff/tif_dir.c
@@ -211,7 +211,7 @@
     }
 bad:
     TIFFErrorExtR(tif, "TIFFSetField",
-                  "%s: Invalid InkNames value; no NUL at given buffer end "
+                  "%s: Invalid InkNames value; no null at given buffer end "
                   "location %" PRIu32 ", after %" PRIu16 " ink",
                   tif->tif_name, slen, i);
     return (0);
@@ -1652,6 +1652,17 @@
 
     _TIFFmemset(&(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
     _TIFFmemset(&(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
+
+    /* Reset some internal parameters for IFD data size checking. */
+    tif->tif_dir.td_dirdatasize_read = 0;
+    tif->tif_dir.td_dirdatasize_write = 0;
+    if (tif->tif_dir.td_dirdatasize_offsets != NULL)
+    {
+        _TIFFfreeExt(tif, tif->tif_dir.td_dirdatasize_offsets);
+        tif->tif_dir.td_dirdatasize_offsets = NULL;
+        tif->tif_dir.td_dirdatasize_Noffsets = 0;
+    }
+    tif->tif_dir.td_iswrittentofile = FALSE;
 }
 #undef CleanupField
 
@@ -1676,18 +1687,23 @@
  */
 int TIFFCreateDirectory(TIFF *tif)
 {
+    /* Free previously allocated memory and setup default values. */
+    TIFFFreeDirectory(tif);
     TIFFDefaultDirectory(tif);
     tif->tif_diroff = 0;
     tif->tif_nextdiroff = 0;
     tif->tif_curoff = 0;
     tif->tif_row = (uint32_t)-1;
     tif->tif_curstrip = (uint32_t)-1;
+    tif->tif_dir.td_iswrittentofile = FALSE;
 
     return 0;
 }
 
 int TIFFCreateCustomDirectory(TIFF *tif, const TIFFFieldArray *infoarray)
 {
+    /* Free previously allocated memory and setup default values. */
+    TIFFFreeDirectory(tif);
     TIFFDefaultDirectory(tif);
 
     /*
@@ -1848,7 +1864,9 @@
             if (((uint64_t)poffa != poff) || (poffb < poffa) ||
                 (poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size))
             {
-                TIFFErrorExtR(tif, module, "Error fetching directory count");
+                TIFFErrorExtR(tif, module,
+                              "%s:%d: %s: Error fetching directory count",
+                              __FILE__, __LINE__, tif->tif_name);
                 *nextdiroff = 0;
                 return (0);
             }
@@ -1877,14 +1895,18 @@
             uint16_t dircount16;
             if (poff > (uint64_t)TIFF_TMSIZE_T_MAX - sizeof(uint64_t))
             {
-                TIFFErrorExtR(tif, module, "Error fetching directory count");
+                TIFFErrorExtR(tif, module,
+                              "%s:%d: %s: Error fetching directory count",
+                              __FILE__, __LINE__, tif->tif_name);
                 return (0);
             }
             poffa = (tmsize_t)poff;
             poffb = poffa + sizeof(uint64_t);
             if (poffb > tif->tif_size)
             {
-                TIFFErrorExtR(tif, module, "Error fetching directory count");
+                TIFFErrorExtR(tif, module,
+                              "%s:%d: %s: Error fetching directory count",
+                              __FILE__, __LINE__, tif->tif_name);
                 return (0);
             }
             _TIFFmemcpy(&dircount64, tif->tif_base + poffa, sizeof(uint64_t));
@@ -1926,8 +1948,9 @@
             if (!SeekOK(tif, *nextdiroff) ||
                 !ReadOK(tif, &dircount, sizeof(uint16_t)))
             {
-                TIFFErrorExtR(tif, module, "%s: Error fetching directory count",
-                              tif->tif_name);
+                TIFFErrorExtR(tif, module,
+                              "%s:%d: %s: Error fetching directory count",
+                              __FILE__, __LINE__, tif->tif_name);
                 return (0);
             }
             if (tif->tif_flags & TIFF_SWAB)
@@ -1953,15 +1976,18 @@
             if (!SeekOK(tif, *nextdiroff) ||
                 !ReadOK(tif, &dircount64, sizeof(uint64_t)))
             {
-                TIFFErrorExtR(tif, module, "%s: Error fetching directory count",
-                              tif->tif_name);
+                TIFFErrorExtR(tif, module,
+                              "%s:%d: %s: Error fetching directory count",
+                              __FILE__, __LINE__, tif->tif_name);
                 return (0);
             }
             if (tif->tif_flags & TIFF_SWAB)
                 TIFFSwabLong8(&dircount64);
             if (dircount64 > 0xFFFF)
             {
-                TIFFErrorExtR(tif, module, "Error fetching directory count");
+                TIFFErrorExtR(tif, module,
+                              "%s:%d: %s: Error fetching directory count",
+                              __FILE__, __LINE__, tif->tif_name);
                 return (0);
             }
             dircount16 = (uint16_t)dircount64;
@@ -2018,6 +2044,8 @@
     {
         ++n;
     }
+    /* Update number of main-IFDs in file. */
+    tif->tif_curdircount = n;
     return (n);
 }
 
@@ -2100,7 +2128,19 @@
         tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
     else
         tif->tif_curdir--;
-    return (TIFFReadDirectory(tif));
+
+    tdir_t curdir = tif->tif_curdir;
+
+    int retval = TIFFReadDirectory(tif);
+
+    if (!retval && tif->tif_curdir == curdir)
+    {
+        /* If tif_curdir has not be incremented, TIFFFetchDirectory() in
+         * TIFFReadDirectory() has failed and tif_curdir shall be set
+         * specifically. */
+        tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+    }
+    return (retval);
 }
 
 /*
@@ -2125,8 +2165,11 @@
     int8_t probablySubIFD = 0;
     if (diroff == 0)
     {
-        /* Special case to invalidate the tif_lastdiroff member. */
+        /* Special case to set tif_diroff=0, which is done in
+         * TIFFReadDirectory() below to indicate that the currently read IFD is
+         * treated as a new, fresh IFD. */
         tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+        tif->tif_dir.td_iswrittentofile = FALSE;
     }
     else
     {
@@ -2136,32 +2179,40 @@
             probablySubIFD = 1;
         }
         /* -1 because TIFFReadDirectory() will increment tif_curdir. */
-        tif->tif_curdir =
-            curdir == 0 ? TIFF_NON_EXISTENT_DIR_NUMBER : curdir - 1;
+        if (curdir >= 1)
+            tif->tif_curdir = curdir - 1;
+        else
+            tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
     }
+    curdir = tif->tif_curdir;
 
     tif->tif_nextdiroff = diroff;
     retval = TIFFReadDirectory(tif);
-    /* If failed, curdir was not incremented in TIFFReadDirectory(), so set it
-     * back, but leave it for diroff==0. */
-    if (!retval && diroff != 0)
+
+    /* tif_curdir is incremented in TIFFReadDirectory(), but if it has not been
+     * incremented, TIFFFetchDirectory() has failed there and tif_curdir shall
+     * be set specifically. */
+    if (!retval && diroff != 0 && tif->tif_curdir == curdir)
     {
-        if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER)
-            tif->tif_curdir = 0;
-        else
-            tif->tif_curdir++;
+        tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
     }
-    if (retval && probablySubIFD)
+
+    if (probablySubIFD)
     {
-        /* Reset IFD list to start new one for SubIFD chain and also start
-         * SubIFD chain with tif_curdir=0. */
-        _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */
-        tif->tif_curdir = 0; /* first directory of new chain */
-        /* add this offset to new IFD list */
-        _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff);
+        if (retval)
+        {
+            /* Reset IFD list to start new one for SubIFD chain and also start
+             * SubIFD chain with tif_curdir=0 for IFD loop checking. */
+            /* invalidate IFD loop lists */
+            _TIFFCleanupIFDOffsetAndNumberMaps(tif);
+            tif->tif_curdir = 0; /* first directory of new chain */
+            /* add this offset to new IFD list */
+            _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff);
+        }
         /* To be able to return from SubIFD or custom-IFD to main-IFD */
         tif->tif_setdirectory_force_absolute = TRUE;
     }
+
     return (retval);
 }
 
@@ -2257,9 +2308,11 @@
     }
     else
     {
+        /* Need local swap because nextdir has to be used unswapped below. */
+        uint64_t nextdir64 = nextdir;
         if (tif->tif_flags & TIFF_SWAB)
-            TIFFSwabLong8(&nextdir);
-        if (!WriteOK(tif, &nextdir, sizeof(uint64_t)))
+            TIFFSwabLong8(&nextdir64);
+        if (!WriteOK(tif, &nextdir64, sizeof(uint64_t)))
         {
             TIFFErrorExtR(tif, module, "Error writing directory link");
             return (0);
@@ -2303,6 +2356,10 @@
     tif->tif_row = (uint32_t)-1;
     tif->tif_curstrip = (uint32_t)-1;
     tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+    if (tif->tif_curdircount > 0)
+        tif->tif_curdircount--;
+    else
+        tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
     _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */
     return (1);
 }
diff --git a/third_party/libtiff/tif_dir.h b/third_party/libtiff/tif_dir.h
index 9eaf22f..ffad085 100644
--- a/third_party/libtiff/tif_dir.h
+++ b/third_party/libtiff/tif_dir.h
@@ -65,6 +65,12 @@
                             tif_dirread.c */
 } TIFFDirEntry;
 
+typedef struct
+{
+    uint64_t offset;
+    uint64_t length;
+} TIFFEntryOffsetAndLength; /* auxiliary for evaluating size of IFD data */
+
 /*
  * Internal format of a TIFF directory entry.
  */
@@ -115,6 +121,9 @@
 #ifdef STRIPBYTECOUNTSORTED_UNUSED
     int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */
 #endif
+    /* Be aware that the parameters of td_stripoffset_entry and
+     * td_stripbytecount_entry are swapped but tdir_offset is not
+     * and has to be swapped when used. */
     TIFFDirEntry td_stripoffset_entry;    /* for deferred loading */
     TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */
     uint16_t td_nsubifd;
@@ -135,6 +144,24 @@
 
     unsigned char
         td_deferstrilearraywriting; /* see TIFFDeferStrileArrayWriting() */
+
+    unsigned char
+        td_iswrittentofile; /* indicates if current IFD is present on file */
+
+    /* LibTIFF writes all data that does not fit into the IFD entries directly
+     * after the IFD tag entry part. When reading, only the IFD data directly
+     * and continuously behind the IFD tags is taken into account for the IFD
+     * data size.*/
+    uint64_t td_dirdatasize_write; /* auxiliary for evaluating size of IFD data
+                                       to be written */
+    uint64_t td_dirdatasize_read;  /* auxiliary for evaluating size of IFD data
+                                       read from file */
+    uint32_t td_dirdatasize_Noffsets; /* auxiliary counter for
+                                         tif_dir.td_dirdatasize_offsets array */
+    TIFFEntryOffsetAndLength
+        *td_dirdatasize_offsets; /* auxiliary array for all offsets of IFD tag
+                                    entries with data outside the IFD tag
+                                    entries. */
 } TIFFDirectory;
 
 /*
@@ -308,11 +335,10 @@
         TIFFDataType field_type; /* type of associated data */
         uint32_t
             field_anonymous; /* if true, this is a unknown / anonymous tag */
-        TIFFSetGetFieldType
-            set_field_type; /* type to be passed to TIFFSetField */
-        TIFFSetGetFieldType
-            get_field_type;              /* type to be passed to TIFFGetField */
-        unsigned short field_bit;        /* bit in fieldsset bit vector */
+        TIFFSetGetFieldType set_field_type; /* type to be passed to TIFFSetField
+                                               and TIFFGetField*/
+        TIFFSetGetFieldType get_field_type; /* not used */
+        unsigned short field_bit;           /* bit in fieldsset bit vector */
         unsigned char field_oktochange;  /* if true, can change while writing */
         unsigned char field_passcount;   /* if true, pass dir count on set */
         char *field_name;                /* ASCII name */
diff --git a/third_party/libtiff/tif_dirinfo.c b/third_party/libtiff/tif_dirinfo.c
index 0e705e8..432e6e1 100644
--- a/third_party/libtiff/tif_dirinfo.c
+++ b/third_party/libtiff/tif_dirinfo.c
@@ -213,8 +213,6 @@
     {TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL},
     {TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL},
 #if 0
-    /* TODO: revert above #if 0 for TIFF 4.6.0 */
-
     /* begin DNG 1.2.0.0 tags */
     {TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL},
     {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL},
@@ -282,9 +280,11 @@
     {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL},
     {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL},
     /* end DNG tags */
+#endif
     /* begin TIFF/EP tags */
     {TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL},
     {TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL},
+#if 0
     /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII.
      * LibTiff defines it as ASCII and converts RATIONAL to an ASCII string. */
     {TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL},
@@ -374,7 +374,7 @@
     {EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL},
     {EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL},
     {EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL},
-    /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! 
+    /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance!
      *    However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values,
      *    which are not treated within LibTiff!! */
     {EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL},
@@ -887,7 +887,7 @@
     if (fld == NULL)
     {
         fld = _TIFFCreateAnonField(tif, tag, dt);
-        if (!_TIFFMergeFields(tif, fld, 1))
+        if (fld == NULL || !_TIFFMergeFields(tif, fld, 1))
             return NULL;
     }
 
@@ -1197,12 +1197,24 @@
     for (i = 0; i < n; i++)
     {
         tp->field_tag = info[i].field_tag;
+        if (info[i].field_readcount < TIFF_VARIABLE2 ||
+            info[i].field_readcount == 0 ||
+            info[i].field_writecount < TIFF_VARIABLE2 ||
+            info[i].field_writecount == 0)
+        {
+            /* The fields (field_readcount) and (field_writecount) may use the
+             * values TIFF_VARIABLE (-1), TIFF_SPP (-2), TIFF_VARIABLE2 (-3). */
+            TIFFErrorExtR(tif, module,
+                          "The value of field_readcount and field_writecount "
+                          "must be greater than or equal to -3 and not zero.");
+            return -1;
+        }
         tp->field_readcount = info[i].field_readcount;
         tp->field_writecount = info[i].field_writecount;
         tp->field_type = info[i].field_type;
         tp->field_anonymous = 0;
         tp->set_field_type =
-            _TIFFSetGetType(info[i].field_type, info[i].field_readcount,
+            _TIFFSetGetType(info[i].field_type, info[i].field_writecount,
                             info[i].field_passcount);
         tp->get_field_type =
             _TIFFSetGetType(info[i].field_type, info[i].field_readcount,
diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
index 4a5015e..2b6e0b4 100644
--- a/third_party/libtiff/tif_dirread.c
+++ b/third_party/libtiff/tif_dirread.c
@@ -1016,16 +1016,7 @@
             err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m);
             if (err != TIFFReadDirEntryErrOk)
                 return (err);
-#if defined(__WIN32__) && (_MSC_VER < 1500)
-            /*
-             * XXX: MSVC 6.0 does not support conversion
-             * of 64-bit integers into floating point
-             * values.
-             */
-            *value = _TIFFUInt64ToFloat(m);
-#else
             *value = (float)m;
-#endif
             return (TIFFReadDirEntryErrOk);
         }
         case TIFF_SLONG8:
@@ -1130,16 +1121,7 @@
             err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m);
             if (err != TIFFReadDirEntryErrOk)
                 return (err);
-#if defined(__WIN32__) && (_MSC_VER < 1500)
-            /*
-             * XXX: MSVC 6.0 does not support conversion
-             * of 64-bit integers into floating point
-             * values.
-             */
-            *value = _TIFFUInt64ToDouble(m);
-#else
             *value = (double)m;
-#endif
             return (TIFFReadDirEntryErrOk);
         }
         case TIFF_SLONG8:
@@ -1308,6 +1290,24 @@
     datasize = (*count) * typesize;
     assert((tmsize_t)datasize > 0);
 
+    if (datasize > 100 * 1024 * 1024)
+    {
+        /* Before allocating a huge amount of memory for corrupted files, check
+         * if size of requested memory is not greater than file size.
+         */
+        const uint64_t filesize = TIFFGetFileSize(tif);
+        if (datasize > filesize)
+        {
+            TIFFWarningExtR(tif, "ReadDirEntryArray",
+                            "Requested memory size for tag %d (0x%x) %" PRIu32
+                            " is greater than filesize %" PRIu64
+                            ". Memory not allocated, tag not read",
+                            direntry->tdir_tag, direntry->tdir_tag, datasize,
+                            filesize);
+            return (TIFFReadDirEntryErrAlloc);
+        }
+    }
+
     if (isMapped(tif) && datasize > (uint64_t)tif->tif_size)
         return TIFFReadDirEntryErrIo;
 
@@ -2886,16 +2886,7 @@
             {
                 if (tif->tif_flags & TIFF_SWAB)
                     TIFFSwabLong8(ma);
-#if defined(__WIN32__) && (_MSC_VER < 1500)
-                /*
-                 * XXX: MSVC 6.0 does not support
-                 * conversion of 64-bit integers into
-                 * floating point values.
-                 */
-                *mb++ = _TIFFUInt64ToFloat(*ma++);
-#else
                 *mb++ = (float)(*ma++);
-#endif
             }
         }
         break;
@@ -3131,16 +3122,7 @@
             {
                 if (tif->tif_flags & TIFF_SWAB)
                     TIFFSwabLong8(ma);
-#if defined(__WIN32__) && (_MSC_VER < 1500)
-                /*
-                 * XXX: MSVC 6.0 does not support
-                 * conversion of 64-bit integers into
-                 * floating point values.
-                 */
-                *mb++ = _TIFFUInt64ToDouble(*ma++);
-#else
                 *mb++ = (double)(*ma++);
-#endif
             }
         }
         break;
@@ -4096,6 +4078,155 @@
 }
 
 /*
+ * To evaluate the IFD data size when reading, save the offset and data size of
+ * all data that does not fit into the IFD entries themselves.
+ */
+static bool EvaluateIFDdatasizeReading(TIFF *tif, TIFFDirEntry *dp)
+{
+    const uint64_t data_width = TIFFDataWidth(dp->tdir_type);
+    if (data_width != 0 && dp->tdir_count > UINT64_MAX / data_width)
+    {
+        TIFFErrorExtR(tif, "EvaluateIFDdatasizeReading",
+                      "Too large IFD data size");
+        return false;
+    }
+    const uint64_t datalength = dp->tdir_count * data_width;
+    if (datalength > ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U))
+    {
+        if (tif->tif_dir.td_dirdatasize_read > UINT64_MAX - datalength)
+        {
+            TIFFErrorExtR(tif, "EvaluateIFDdatasizeReading",
+                          "Too large IFD data size");
+            return false;
+        }
+        tif->tif_dir.td_dirdatasize_read += datalength;
+        if (!(tif->tif_flags & TIFF_BIGTIFF))
+        {
+            /* The offset of TIFFDirEntry are not swapped when read in. That has
+             * to be done when used. */
+            uint32_t offset = dp->tdir_offset.toff_long;
+            if (tif->tif_flags & TIFF_SWAB)
+                TIFFSwabLong(&offset);
+            tif->tif_dir
+                .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets]
+                .offset = (uint64_t)offset;
+        }
+        else
+        {
+            tif->tif_dir
+                .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets]
+                .offset = dp->tdir_offset.toff_long8;
+            if (tif->tif_flags & TIFF_SWAB)
+                TIFFSwabLong8(
+                    &tif->tif_dir
+                         .td_dirdatasize_offsets[tif->tif_dir
+                                                     .td_dirdatasize_Noffsets]
+                         .offset);
+        }
+        tif->tif_dir
+            .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets]
+            .length = datalength;
+        tif->tif_dir.td_dirdatasize_Noffsets++;
+    }
+    return true;
+}
+
+/*
+ * Compare function for qsort() sorting TIFFEntryOffsetAndLength array entries.
+ */
+static int cmpTIFFEntryOffsetAndLength(const void *a, const void *b)
+{
+    const TIFFEntryOffsetAndLength *ta = (const TIFFEntryOffsetAndLength *)a;
+    const TIFFEntryOffsetAndLength *tb = (const TIFFEntryOffsetAndLength *)b;
+    /* Compare offsets */
+    if (ta->offset > tb->offset)
+        return 1;
+    else if (ta->offset < tb->offset)
+        return -1;
+    else
+        return 0;
+}
+
+/*
+ * Determine the IFD data size after reading an IFD from the file that can be
+ * overwritten and saving it in tif_dir.td_dirdatasize_read. This data size
+ * includes the IFD entries themselves as well as the data that does not fit
+ * directly into the IFD entries but is located directly after the IFD entries
+ * in the file.
+ */
+static void CalcFinalIFDdatasizeReading(TIFF *tif, uint16_t dircount)
+{
+    /* IFD data size is only needed if file-writing is enabled.
+     * This also avoids the seek() to EOF to determine the file size, which
+     * causes the stdin-streaming-friendly mode of libtiff for GDAL to fail. */
+    if (tif->tif_mode == O_RDONLY)
+        return;
+
+    /* Sort TIFFEntryOffsetAndLength array in ascending order. */
+    qsort(tif->tif_dir.td_dirdatasize_offsets,
+          tif->tif_dir.td_dirdatasize_Noffsets,
+          sizeof(TIFFEntryOffsetAndLength), cmpTIFFEntryOffsetAndLength);
+
+    /* Get offset of end of IFD entry space. */
+    uint64_t IFDendoffset;
+    if (!(tif->tif_flags & TIFF_BIGTIFF))
+        IFDendoffset = tif->tif_diroff + 2 + dircount * 12 + 4;
+    else
+        IFDendoffset = tif->tif_diroff + 8 + dircount * 20 + 8;
+
+    /* Check which offsets are right behind IFD entries. However, LibTIFF
+     * increments the writing address for every external data to an even offset.
+     * Thus gaps of 1 byte can occur. */
+    uint64_t size = 0;
+    uint64_t offset;
+    uint32_t i;
+    for (i = 0; i < tif->tif_dir.td_dirdatasize_Noffsets; i++)
+    {
+        offset = tif->tif_dir.td_dirdatasize_offsets[i].offset;
+        if (offset == IFDendoffset)
+        {
+            size += tif->tif_dir.td_dirdatasize_offsets[i].length;
+            IFDendoffset += tif->tif_dir.td_dirdatasize_offsets[i].length;
+        }
+        else if (offset == IFDendoffset + 1)
+        {
+            /* Add gap byte after previous IFD data set. */
+            size += tif->tif_dir.td_dirdatasize_offsets[i].length + 1;
+            IFDendoffset += tif->tif_dir.td_dirdatasize_offsets[i].length;
+        }
+        else
+        {
+            /* Further data is no more continuously after IFD */
+            break;
+        }
+    }
+    /* Check for gap byte of some easy cases. This should cover 90% of cases.
+     * Otherwise, IFD will be re-written even it might be safely overwritten. */
+    if (tif->tif_nextdiroff != 0)
+    {
+        if (tif->tif_nextdiroff == IFDendoffset + 1)
+            size++;
+    }
+    else
+    {
+        /* Check for IFD data ends at EOF. Then IFD can always be safely
+         * overwritten. */
+        offset = TIFFSeekFile(tif, 0, SEEK_END);
+        if (offset == IFDendoffset)
+        {
+            tif->tif_dir.td_dirdatasize_read = UINT64_MAX;
+            return;
+        }
+    }
+
+    /* Finally, add the size of the IFD tag entries themselves. */
+    if (!(tif->tif_flags & TIFF_BIGTIFF))
+        tif->tif_dir.td_dirdatasize_read = 2 + dircount * 12 + 4 + size;
+    else
+        tif->tif_dir.td_dirdatasize_read = 8 + dircount * 20 + 8 + size;
+} /*-- CalcFinalIFDdatasizeReading() --*/
+
+/*
  * Read the next TIFF directory from a file and convert it to the internal
  * format. We read directories sequentially.
  */
@@ -4150,7 +4281,6 @@
         tif->tif_curdir = 0;
     else
         tif->tif_curdir++;
-    (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
 
     TIFFReadDirectoryCheckOrder(tif, dir, dircount);
 
@@ -4180,8 +4310,27 @@
     tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS;
 
     /* free any old stuff and reinit */
+    (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
     TIFFFreeDirectory(tif);
     TIFFDefaultDirectory(tif);
+
+    /* After setup a fresh directory indicate that now active IFD is also
+     * present on file, even if its entries could not be read successfully
+     * below.  */
+    tif->tif_dir.td_iswrittentofile = TRUE;
+
+    /* Allocate arrays for offset values outside IFD entry for IFD data size
+     * checking. Note: Counter are reset within TIFFFreeDirectory(). */
+    tif->tif_dir.td_dirdatasize_offsets =
+        (TIFFEntryOffsetAndLength *)_TIFFmallocExt(
+            tif, dircount * sizeof(TIFFEntryOffsetAndLength));
+    if (tif->tif_dir.td_dirdatasize_offsets == NULL)
+    {
+        TIFFErrorExtR(
+            tif, module,
+            "Failed to allocate memory for counting IFD data size at reading");
+        goto bad;
+    }
     /*
      * Electronic Arts writes gray-scale TIFF files
      * without a PlanarConfiguration directory entry.
@@ -4260,11 +4409,9 @@
                                 dp->tdir_tag, dp->tdir_tag);
                 /* the following knowingly leaks the
                    anonymous field structure */
-                if (!_TIFFMergeFields(
-                        tif,
-                        _TIFFCreateAnonField(tif, dp->tdir_tag,
-                                             (TIFFDataType)dp->tdir_type),
-                        1))
+                const TIFFField *fld = _TIFFCreateAnonField(
+                    tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type);
+                if (fld == NULL || !_TIFFMergeFields(tif, fld, 1))
                 {
                     TIFFWarningExtR(
                         tif, module,
@@ -4381,6 +4528,8 @@
                         uint16_t value;
                         enum TIFFReadDirEntryErr err;
                         err = TIFFReadDirEntryShort(tif, dp, &value);
+                        if (!EvaluateIFDdatasizeReading(tif, dp))
+                            goto bad;
                         if (err == TIFFReadDirEntryErrCount)
                             err =
                                 TIFFReadDirEntryPersampleShort(tif, dp, &value);
@@ -4411,6 +4560,8 @@
                         err = TIFFReadDirEntryErrCount;
                     else
                         err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                        goto bad;
                     if (err != TIFFReadDirEntryErrOk)
                     {
                         fip = TIFFFieldWithTag(tif, dp->tdir_tag);
@@ -4430,6 +4581,7 @@
                 break;
                 case TIFFTAG_STRIPOFFSETS:
                 case TIFFTAG_TILEOFFSETS:
+                {
                     switch (dp->tdir_type)
                     {
                         case TIFF_SHORT:
@@ -4452,9 +4604,13 @@
                     }
                     _TIFFmemcpy(&(tif->tif_dir.td_stripoffset_entry), dp,
                                 sizeof(TIFFDirEntry));
-                    break;
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                        goto bad;
+                }
+                break;
                 case TIFFTAG_STRIPBYTECOUNTS:
                 case TIFFTAG_TILEBYTECOUNTS:
+                {
                     switch (dp->tdir_type)
                     {
                         case TIFF_SHORT:
@@ -4477,7 +4633,10 @@
                     }
                     _TIFFmemcpy(&(tif->tif_dir.td_stripbytecount_entry), dp,
                                 sizeof(TIFFDirEntry));
-                    break;
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                        goto bad;
+                }
+                break;
                 case TIFFTAG_COLORMAP:
                 case TIFFTAG_TRANSFERFUNCTION:
                 {
@@ -4531,6 +4690,8 @@
                         err = TIFFReadDirEntryErrCount;
                     else
                         err = TIFFReadDirEntryShortArray(tif, dp, &value);
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                        goto bad;
                     if (err != TIFFReadDirEntryErrOk)
                     {
                         fip = TIFFFieldWithTag(tif, dp->tdir_tag);
@@ -4621,9 +4782,12 @@
                 default:
                     (void)TIFFFetchNormalTag(tif, dp, TRUE);
                     break;
-            }
-        } /* -- if (!dp->tdir_ignore) */
-    }     /* -- for-loop -- */
+            } /* -- switch (dp->tdir_tag) -- */
+        }     /* -- if (!dp->tdir_ignore) */
+    }         /* -- for-loop -- */
+
+    /* Evaluate final IFD data size. */
+    CalcFinalIFDdatasizeReading(tif, dircount);
 
     /*
      * OJPEG hack:
@@ -5040,7 +5204,7 @@
     if (dir)
         _TIFFfreeExt(tif, dir);
     return (0);
-}
+} /*-- TIFFReadDirectory() --*/
 
 static void TIFFReadDirectoryCheckOrder(TIFF *tif, TIFFDirEntry *dir,
                                         uint16_t dircount)
@@ -5124,8 +5288,7 @@
     uint16_t di;
     const TIFFField *fip;
     uint32_t fii;
-    (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
-    _TIFFSetupFields(tif, infoarray);
+
     dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL);
     if (!dircount)
     {
@@ -5134,9 +5297,56 @@
                       diroff);
         return 0;
     }
-    TIFFFreeDirectory(tif);
-    _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory));
     TIFFReadDirectoryCheckOrder(tif, dir, dircount);
+
+    /*
+     * Mark duplicates of any tag to be ignored (bugzilla 1994)
+     * to avoid certain pathological problems.
+     */
+    {
+        TIFFDirEntry *ma;
+        uint16_t mb;
+        for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
+        {
+            TIFFDirEntry *na;
+            uint16_t nb;
+            for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
+            {
+                if (ma->tdir_tag == na->tdir_tag)
+                {
+                    na->tdir_ignore = TRUE;
+                }
+            }
+        }
+    }
+
+    /* Free any old stuff and reinit. */
+    (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
+    TIFFFreeDirectory(tif);
+    /* Even if custom directories do not need the default settings of a standard
+     * IFD, the pointer to the TIFFSetField() and TIFFGetField() (i.e.
+     * tif->tif_tagmethods.vsetfield and tif->tif_tagmethods.vgetfield) need to
+     * be initialized, which is done in TIFFDefaultDirectory().
+     * After that, the field array for the custom tags needs to be setup again.
+     */
+    TIFFDefaultDirectory(tif);
+    _TIFFSetupFields(tif, infoarray);
+
+    /* Allocate arrays for offset values outside IFD entry for IFD data size
+     * checking. Note: Counter are reset within TIFFFreeDirectory(). */
+    tif->tif_dir.td_dirdatasize_offsets =
+        (TIFFEntryOffsetAndLength *)_TIFFmallocExt(
+            tif, dircount * sizeof(TIFFEntryOffsetAndLength));
+    if (tif->tif_dir.td_dirdatasize_offsets == NULL)
+    {
+        TIFFErrorExtR(
+            tif, module,
+            "Failed to allocate memory for counting IFD data size at reading");
+        if (dir)
+            _TIFFfreeExt(tif, dir);
+        return 0;
+    }
+
     for (di = 0, dp = dir; di < dircount; di++, dp++)
     {
         TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii);
@@ -5146,11 +5356,9 @@
                             "Unknown field with tag %" PRIu16 " (0x%" PRIx16
                             ") encountered",
                             dp->tdir_tag, dp->tdir_tag);
-            if (!_TIFFMergeFields(
-                    tif,
-                    _TIFFCreateAnonField(tif, dp->tdir_tag,
-                                         (TIFFDataType)dp->tdir_type),
-                    1))
+            const TIFFField *fld = _TIFFCreateAnonField(
+                tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type);
+            if (fld == NULL || !_TIFFMergeFields(tif, fld, 1))
             {
                 TIFFWarningExtR(tif, module,
                                 "Registering anonymous field with tag %" PRIu16
@@ -5233,6 +5441,9 @@
             } /*-- if (!dp->tdir_ignore) */
         }
     }
+    /* Evaluate final IFD data size. */
+    CalcFinalIFDdatasizeReading(tif, dircount);
+
     /* To be able to return from SubIFD or custom-IFD to main-IFD */
     tif->tif_setdirectory_force_absolute = TRUE;
     if (dir)
@@ -5246,9 +5457,7 @@
  */
 int TIFFReadEXIFDirectory(TIFF *tif, toff_t diroff)
 {
-    const TIFFFieldArray *exifFieldArray;
-    exifFieldArray = _TIFFGetExifFields();
-    return TIFFReadCustomDirectory(tif, diroff, exifFieldArray);
+    return TIFFReadCustomDirectory(tif, diroff, _TIFFGetExifFields());
 }
 
 /*
@@ -5256,9 +5465,7 @@
  */
 int TIFFReadGPSDirectory(TIFF *tif, toff_t diroff)
 {
-    const TIFFFieldArray *gpsFieldArray;
-    gpsFieldArray = _TIFFGetGpsFields();
-    return TIFFReadCustomDirectory(tif, diroff, gpsFieldArray);
+    return TIFFReadCustomDirectory(tif, diroff, _TIFFGetGpsFields());
 }
 
 static int EstimateStripByteCounts(TIFF *tif, TIFFDirEntry *dir,
@@ -5274,6 +5481,24 @@
     if (!_TIFFFillStrilesInternal(tif, 0))
         return -1;
 
+    const uint64_t allocsize = (uint64_t)td->td_nstrips * sizeof(uint64_t);
+    uint64_t filesize = 0;
+    if (allocsize > 100 * 1024 * 1024)
+    {
+        /* Before allocating a huge amount of memory for corrupted files, check
+         * if size of requested memory is not greater than file size. */
+        filesize = TIFFGetFileSize(tif);
+        if (allocsize > filesize)
+        {
+            TIFFWarningExtR(
+                tif, module,
+                "Requested memory size for StripByteCounts of %" PRIu64
+                " is greater than filesize %" PRIu64 ". Memory not allocated",
+                allocsize, filesize);
+            return -1;
+        }
+    }
+
     if (td->td_stripbytecount_p)
         _TIFFfreeExt(tif, td->td_stripbytecount_p);
     td->td_stripbytecount_p = (uint64_t *)_TIFFCheckMalloc(
@@ -5284,9 +5509,7 @@
     if (td->td_compression != COMPRESSION_NONE)
     {
         uint64_t space;
-        uint64_t filesize;
         uint16_t n;
-        filesize = TIFFGetFileSize(tif);
         if (!(tif->tif_flags & TIFF_BIGTIFF))
             space = sizeof(TIFFHeaderClassic) + 2 + dircount * 12 + 4;
         else
@@ -5322,6 +5545,8 @@
                 return -1;
             space += datasize;
         }
+        if (filesize == 0)
+            filesize = TIFFGetFileSize(tif);
         if (filesize < space)
             /* we should perhaps return in error ? */
             space = filesize;
@@ -5929,6 +6154,20 @@
                           "directories not supported");
             return 0;
         }
+        /* Before allocating a huge amount of memory for corrupted files, check
+         * if size of requested memory is not greater than file size. */
+        uint64_t filesize = TIFFGetFileSize(tif);
+        uint64_t allocsize = (uint64_t)dircount16 * dirsize;
+        if (allocsize > filesize)
+        {
+            TIFFWarningExtR(
+                tif, module,
+                "Requested memory size for TIFF directory of %" PRIu64
+                " is greater than filesize %" PRIu64
+                ". Memory not allocated, TIFF directory not read",
+                allocsize, filesize);
+            return 0;
+        }
         origdir = _TIFFCheckMalloc(tif, dircount16, dirsize,
                                    "to read TIFF directory");
         if (origdir == NULL)
@@ -5976,6 +6215,8 @@
             }
         }
     }
+    /* No check against filesize needed here because "dir" should have same size
+     * than "origdir" checked above. */
     dir = (TIFFDirEntry *)_TIFFCheckMalloc(
         tif, dircount16, sizeof(TIFFDirEntry), "to read TIFF directory");
     if (dir == 0)
@@ -6088,6 +6329,12 @@
                         }
                     }
                 }
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != NULL)
+                        _TIFFfreeExt(tif, data);
+                    return (0);
+                }
                 if (mb + 1 < (uint32_t)dp->tdir_count)
                     TIFFWarningExtR(
                         tif, module,
@@ -6097,15 +6344,15 @@
                         fip->field_name);
                 else if (mb + 1 > (uint32_t)dp->tdir_count)
                 {
-                    uint8_t *o;
-                    TIFFWarningExtR(
-                        tif, module,
-                        "ASCII value for tag \"%s\" does not end in null byte",
-                        fip->field_name);
+                    TIFFWarningExtR(tif, module,
+                                    "ASCII value for tag \"%s\" does not end "
+                                    "in null byte. Forcing it to be null",
+                                    fip->field_name);
                     /* TIFFReadDirEntryArrayWithLimit() ensures this can't be
                      * larger than MAX_SIZE_TAG_DATA */
                     assert((uint32_t)dp->tdir_count + 1 == dp->tdir_count + 1);
-                    o = _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1);
+                    uint8_t *o =
+                        _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1);
                     if (o == NULL)
                     {
                         if (data != NULL)
@@ -6215,6 +6462,8 @@
             err = TIFFReadDirEntryLong8(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                    return 0;
                 if (!TIFFSetField(tif, dp->tdir_tag, data))
                     return (0);
             }
@@ -6228,6 +6477,8 @@
             err = TIFFReadDirEntrySlong8(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                    return 0;
                 if (!TIFFSetField(tif, dp->tdir_tag, data))
                     return (0);
             }
@@ -6241,6 +6492,8 @@
             err = TIFFReadDirEntryFloat(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                    return 0;
                 if (!TIFFSetField(tif, dp->tdir_tag, data))
                     return (0);
             }
@@ -6254,6 +6507,8 @@
             err = TIFFReadDirEntryDouble(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                    return 0;
                 if (!TIFFSetField(tif, dp->tdir_tag, data))
                     return (0);
             }
@@ -6267,6 +6522,8 @@
             err = TIFFReadDirEntryIfd8(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                    return 0;
                 if (!TIFFSetField(tif, dp->tdir_tag, data))
                     return (0);
             }
@@ -6316,6 +6573,12 @@
                 err = TIFFReadDirEntryByteArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6345,6 +6608,12 @@
                 err = TIFFReadDirEntrySbyteArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6374,6 +6643,12 @@
                 err = TIFFReadDirEntryShortArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6403,6 +6678,12 @@
                 err = TIFFReadDirEntrySshortArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6432,6 +6713,12 @@
                 err = TIFFReadDirEntryLongArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6461,6 +6748,12 @@
                 err = TIFFReadDirEntrySlongArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6490,6 +6783,12 @@
                 err = TIFFReadDirEntryLong8Array(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6519,6 +6818,12 @@
                 err = TIFFReadDirEntrySlong8Array(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6548,6 +6853,12 @@
                 err = TIFFReadDirEntryFloatArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6579,6 +6890,12 @@
                 err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag, data);
                     if (data != 0)
@@ -6601,16 +6918,39 @@
                 err = TIFFReadDirEntryByteArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     if (data != 0 && dp->tdir_count > 0 &&
                         data[dp->tdir_count - 1] != '\0')
                     {
-                        TIFFWarningExtR(
-                            tif, module,
-                            "ASCII value for tag \"%s\" does not end in null "
-                            "byte. Forcing it to be null",
-                            fip->field_name);
-                        data[dp->tdir_count - 1] = '\0';
+                        TIFFWarningExtR(tif, module,
+                                        "ASCII value for ASCII array tag "
+                                        "\"%s\" does not end in null "
+                                        "byte. Forcing it to be null",
+                                        fip->field_name);
+                        /* Enlarge buffer and add terminating null. */
+                        uint8_t *o =
+                            _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1);
+                        if (o == NULL)
+                        {
+                            if (data != NULL)
+                                _TIFFfreeExt(tif, data);
+                            return (0);
+                        }
+                        if (dp->tdir_count > 0)
+                        {
+                            _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count);
+                        }
+                        o[(uint32_t)dp->tdir_count] = 0;
+                        dp->tdir_count++; /* Increment for added null. */
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        data = o;
                     }
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6634,6 +6974,12 @@
                 err = TIFFReadDirEntryByteArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6657,6 +7003,12 @@
                 err = TIFFReadDirEntrySbyteArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6680,6 +7032,12 @@
                 err = TIFFReadDirEntryShortArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6703,6 +7061,12 @@
                 err = TIFFReadDirEntrySshortArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6726,6 +7090,12 @@
                 err = TIFFReadDirEntryLongArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6749,6 +7119,12 @@
                 err = TIFFReadDirEntrySlongArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6772,6 +7148,12 @@
                 err = TIFFReadDirEntryLong8Array(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6795,6 +7177,12 @@
                 err = TIFFReadDirEntrySlong8Array(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6818,6 +7206,12 @@
                 err = TIFFReadDirEntryFloatArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6841,6 +7235,12 @@
                 err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6864,6 +7264,12 @@
                 err = TIFFReadDirEntryIfd8Array(tif, dp, &data);
                 if (err == TIFFReadDirEntryErrOk)
                 {
+                    if (!EvaluateIFDdatasizeReading(tif, dp))
+                    {
+                        if (data != 0)
+                            _TIFFfreeExt(tif, data);
+                        return 0;
+                    }
                     int m;
                     m = TIFFSetField(tif, dp->tdir_tag,
                                      (uint16_t)(dp->tdir_count), data);
@@ -6883,15 +7289,39 @@
             err = TIFFReadDirEntryByteArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 if (data != 0 && dp->tdir_count > 0 &&
                     data[dp->tdir_count - 1] != '\0')
                 {
-                    TIFFWarningExtR(tif, module,
-                                    "ASCII value for tag \"%s\" does not end "
-                                    "in null byte. Forcing it to be null",
-                                    fip->field_name);
-                    data[dp->tdir_count - 1] = '\0';
+                    TIFFWarningExtR(
+                        tif, module,
+                        "ASCII value for ASCII array tag \"%s\" does not end "
+                        "in null byte. Forcing it to be null",
+                        fip->field_name);
+                    /* Enlarge buffer and add terminating null. */
+                    uint8_t *o =
+                        _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1);
+                    if (o == NULL)
+                    {
+                        if (data != NULL)
+                            _TIFFfreeExt(tif, data);
+                        return (0);
+                    }
+                    if (dp->tdir_count > 0)
+                    {
+                        _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count);
+                    }
+                    o[(uint32_t)dp->tdir_count] = 0;
+                    dp->tdir_count++; /* Increment for added null. */
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    data = o;
                 }
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -6935,6 +7365,12 @@
             }
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, count, data);
                 if (data != 0)
@@ -6952,6 +7388,12 @@
             err = TIFFReadDirEntrySbyteArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -6970,6 +7412,12 @@
             err = TIFFReadDirEntryShortArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -6988,6 +7436,12 @@
             err = TIFFReadDirEntrySshortArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7006,6 +7460,12 @@
             err = TIFFReadDirEntryLongArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7024,6 +7484,12 @@
             err = TIFFReadDirEntrySlongArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7042,6 +7508,12 @@
             err = TIFFReadDirEntryLong8Array(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7060,6 +7532,12 @@
             err = TIFFReadDirEntrySlong8Array(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7078,6 +7556,12 @@
             err = TIFFReadDirEntryFloatArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7096,6 +7580,12 @@
             err = TIFFReadDirEntryDoubleArray(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7114,6 +7604,12 @@
             err = TIFFReadDirEntryIfd8Array(tif, dp, &data);
             if (err == TIFFReadDirEntryErrOk)
             {
+                if (!EvaluateIFDdatasizeReading(tif, dp))
+                {
+                    if (data != 0)
+                        _TIFFfreeExt(tif, data);
+                    return 0;
+                }
                 int m;
                 m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count),
                                  data);
@@ -7172,6 +7668,25 @@
             return (0);
         }
 
+        const uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t);
+        if (allocsize > 100 * 1024 * 1024)
+        {
+            /* Before allocating a huge amount of memory for corrupted files,
+             * check if size of requested memory is not greater than file size.
+             */
+            const uint64_t filesize = TIFFGetFileSize(tif);
+            if (allocsize > filesize)
+            {
+                TIFFWarningExtR(
+                    tif, module,
+                    "Requested memory size for StripArray of %" PRIu64
+                    " is greater than filesize %" PRIu64
+                    ". Memory not allocated",
+                    allocsize, filesize);
+                _TIFFfreeExt(tif, data);
+                return (0);
+            }
+        }
         resizeddata = (uint64_t *)_TIFFCheckMalloc(
             tif, nstrips, sizeof(uint64_t), "for strip array");
         if (resizeddata == 0)
@@ -7271,6 +7786,26 @@
     }
     bytecount = last_offset + last_bytecount - offset;
 
+    /* Before allocating a huge amount of memory for corrupted files, check if
+     * size of StripByteCount and StripOffset tags is not greater than
+     * file size.
+     */
+    const uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t) * 2;
+    if (allocsize > 100 * 1024 * 1024)
+    {
+        const uint64_t filesize = TIFFGetFileSize(tif);
+        if (allocsize > filesize)
+        {
+            TIFFWarningExtR(tif, "allocChoppedUpStripArrays",
+                            "Requested memory size for StripByteCount and "
+                            "StripOffsets %" PRIu64
+                            " is greater than filesize %" PRIu64
+                            ". Memory not allocated",
+                            allocsize, filesize);
+            return;
+        }
+    }
+
     newcounts =
         (uint64_t *)_TIFFCheckMalloc(tif, nstrips, sizeof(uint64_t),
                                      "for chopped \"StripByteCounts\" array");
@@ -7371,7 +7906,7 @@
     /*
      * never increase the number of rows per strip
      */
-    if (rowsperstrip >= td->td_rowsperstrip)
+    if (rowsperstrip >= td->td_rowsperstrip || rowsperstrip == 0)
         return;
     nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
     if (nstrips == 0)
@@ -7467,6 +8002,8 @@
     stripbytes = rowblocksperstrip * rowblockbytes;
     assert(stripbytes <= 0x7FFFFFFFUL);
 
+    if (rowsperstrip == 0)
+        return;
     nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
     if (nstrips == 0)
         return;
diff --git a/third_party/libtiff/tif_dirwrite.c b/third_party/libtiff/tif_dirwrite.c
index d8844bb..facdeaf 100644
--- a/third_party/libtiff/tif_dirwrite.c
+++ b/third_party/libtiff/tif_dirwrite.c
@@ -303,12 +303,14 @@
 }
 
 /*
- * Similar to TIFFWriteDirectory(), but if the directory has already
+ * Similar to TIFFWriteDirectorySec(), but if the directory has already
  * been written once, it is relocated to the end of the file, in case it
  * has changed in size.  Note that this will result in the loss of the
  * previously used directory space.
  */
-int TIFFRewriteDirectory(TIFF *tif)
+
+static int TIFFRewriteDirectorySec(TIFF *tif, int isimage, int imagedone,
+                                   uint64_t *pdiroff)
 {
     static const char module[] = "TIFFRewriteDirectory";
 
@@ -464,10 +466,20 @@
     }
 
     /*
-     * Now use TIFFWriteDirectory() normally.
+     * Now use TIFFWriteDirectorySec() normally.
      */
+    return TIFFWriteDirectorySec(tif, isimage, imagedone, pdiroff);
+} /*-- TIFFRewriteDirectorySec() --*/
 
-    return TIFFWriteDirectory(tif);
+/*
+ * Similar to TIFFWriteDirectory(), but if the directory has already
+ * been written once, it is relocated to the end of the file, in case it
+ * has changed in size.  Note that this will result in the loss of the
+ * previously used directory space.
+ */
+int TIFFRewriteDirectory(TIFF *tif)
+{
+    return TIFFRewriteDirectorySec(tif, TRUE, TRUE, NULL);
 }
 
 static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
@@ -542,7 +554,12 @@
     dirsize = 0;
     while (1)
     {
+        /* The first loop only determines "ndir" and uses TIFFLinkDirectory() to
+         * set the offset at which the IFD is to be written to the file.
+         * The second loop writes IFD entries to the file. */
         ndir = 0;
+        if (dir == NULL)
+            tif->tif_dir.td_dirdatasize_write = 0;
         if (isimage)
         {
             if (TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS))
@@ -852,7 +869,7 @@
                     if ((o->field_bit >= FIELD_CODEC) &&
                         (TIFFFieldSet(tif, o->field_bit)))
                     {
-                        switch (o->get_field_type)
+                        switch (o->set_field_type)
                         {
                             case TIFF_SETGET_ASCII:
                             {
@@ -1085,8 +1102,18 @@
                     break;
             }
         }
+        /* "break" if IFD has been written above in second pass.*/
         if (dir != NULL)
             break;
+
+        /* Evaluate IFD data size: Finally, add the size of the IFD tag entries
+         * themselves. */
+        if (!(tif->tif_flags & TIFF_BIGTIFF))
+            tif->tif_dir.td_dirdatasize_write += 2 + ndir * 12 + 4;
+        else
+            tif->tif_dir.td_dirdatasize_write += 8 + ndir * 20 + 8;
+
+        /* Setup a new directory within first pass. */
         dir = _TIFFmallocExt(tif, ndir * sizeof(TIFFDirEntry));
         if (dir == NULL)
         {
@@ -1095,18 +1122,58 @@
         }
         if (isimage)
         {
-            if ((tif->tif_diroff == 0) && (!TIFFLinkDirectory(tif)))
-                goto bad;
+            /* Check, weather the IFD to be written is new or an already written
+             * IFD can be overwritten or needs to be re-written to a different
+             * location in the file because the IFD is extended with additional
+             * tags or the IFD data size is increased.
+             * - tif_diroff == 0, if a new directory has to be linked.
+             * - tif_diroff != 0, IFD has been re-read from file and will be
+             *   overwritten or re-written.
+             */
+            if (tif->tif_diroff == 0)
+            {
+                if (!TIFFLinkDirectory(tif))
+                    goto bad;
+            }
+            else if (tif->tif_dir.td_dirdatasize_write >
+                     tif->tif_dir.td_dirdatasize_read)
+            {
+                if (dir != NULL)
+                {
+                    _TIFFfreeExt(tif, dir);
+                    dir = NULL;
+                }
+                if (!TIFFRewriteDirectorySec(tif, isimage, imagedone, pdiroff))
+                    goto bad;
+                return (1);
+            }
         }
         else
-            tif->tif_diroff =
-                (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1));
+        {
+            /* For !isimage, which means custom-IFD like EXIFIFD or
+             * checkpointing an IFD, determine whether to overwrite or append at
+             * the end of the file.
+             */
+            if (!((tif->tif_dir.td_dirdatasize_read > 0) &&
+                  (tif->tif_dir.td_dirdatasize_write <=
+                   tif->tif_dir.td_dirdatasize_read)))
+            {
+                /* Append at end of file and increment to an even offset. */
+                tif->tif_diroff =
+                    (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1));
+            }
+        }
+        /* Return IFD offset */
         if (pdiroff != NULL)
             *pdiroff = tif->tif_diroff;
         if (!(tif->tif_flags & TIFF_BIGTIFF))
             dirsize = 2 + ndir * 12 + 4;
         else
             dirsize = 8 + ndir * 20 + 8;
+        /* Append IFD data stright after the IFD tag entries.
+         * Data that does not fit into an IFD tag entry is written to the file
+         * in the second pass of the while loop. That offset is stored in "dir".
+         */
         tif->tif_dataoff = tif->tif_diroff + dirsize;
         if (!(tif->tif_flags & TIFF_BIGTIFF))
             tif->tif_dataoff = (uint32_t)tif->tif_dataoff;
@@ -1118,16 +1185,12 @@
         }
         if (tif->tif_dataoff & 1)
             tif->tif_dataoff++;
-        if (isimage)
-        {
-            if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER)
-                tif->tif_curdir = 0;
-            else
-                tif->tif_curdir++;
-        }
-    }
+    } /* while() */
     if (isimage)
     {
+        /* For SubIFDs remember offset of SubIFD tag within main IFD.
+         * However, might be already done in TIFFWriteDirectoryTagSubifd() if
+         * there are more than one SubIFD. */
         if (TIFFFieldSet(tif, FIELD_SUBIFD) && (tif->tif_subifdoff == 0))
         {
             uint32_t na;
@@ -1148,6 +1211,8 @@
                 tif->tif_subifdoff = tif->tif_diroff + 8 + na * 20 + 12;
         }
     }
+    /* Copy/swab IFD entries from "dir" into "dirmem",
+     * which is then written to file. */
     dirmem = _TIFFmallocExt(tif, dirsize);
     if (dirmem == NULL)
     {
@@ -1227,7 +1292,8 @@
     dir = NULL;
     if (!SeekOK(tif, tif->tif_diroff))
     {
-        TIFFErrorExtR(tif, module, "IO error writing directory");
+        TIFFErrorExtR(tif, module,
+                      "IO error writing directory at seek to offset");
         goto bad;
     }
     if (!WriteOK(tif, dirmem, (tmsize_t)dirsize))
@@ -1236,18 +1302,83 @@
         goto bad;
     }
     _TIFFfreeExt(tif, dirmem);
+
+    /* Increment tif_curdir if IFD wasn't already written to file and no error
+     * occurred during IFD writing above. */
+    if (isimage && !tif->tif_dir.td_iswrittentofile)
+    {
+        if (!((tif->tif_flags & TIFF_INSUBIFD) &&
+              !(TIFFFieldSet(tif, FIELD_SUBIFD))))
+        {
+            /*-- Normal main-IFD case --*/
+            if (tif->tif_curdircount != TIFF_NON_EXISTENT_DIR_NUMBER)
+            {
+                tif->tif_curdir = tif->tif_curdircount;
+            }
+            else
+            {
+                /*ToDo SU: NEW_IFD_CURDIR_INCREMENTING:  Delete this
+                 * unexpected case after some testing time. */
+                /* Attention: tif->tif_curdircount is already set within
+                 * TIFFNumberOfDirectories() */
+                tif->tif_curdircount = TIFFNumberOfDirectories(tif);
+                tif->tif_curdir = tif->tif_curdircount;
+                TIFFErrorExtR(
+                    tif, module,
+                    "tif_curdircount is TIFF_NON_EXISTENT_DIR_NUMBER, "
+                    "not expected !! Line %d",
+                    __LINE__);
+                goto bad;
+            }
+        }
+        else
+        {
+            /*-- SubIFD case -- */
+            /* tif_curdir is always set to 0 for all SubIFDs. */
+            tif->tif_curdir = 0;
+        }
+    }
+    /* Increment tif_curdircount only if main-IFD of an image was not already
+     * present on file. */
+    /* Check in combination with (... && !(TIFFFieldSet(tif, FIELD_SUBIFD)))
+     * is necessary here because TIFF_INSUBIFD was already set above for the
+     * next SubIFD when this main-IFD (with FIELD_SUBIFD) is currently being
+     * written. */
+    if (isimage && !tif->tif_dir.td_iswrittentofile &&
+        !((tif->tif_flags & TIFF_INSUBIFD) &&
+          !(TIFFFieldSet(tif, FIELD_SUBIFD))))
+        tif->tif_curdircount++;
+
+    tif->tif_dir.td_iswrittentofile = TRUE;
+
+    /* Reset SubIFD writing stage after last SubIFD has been written. */
+    if (imagedone && (tif->tif_flags & TIFF_INSUBIFD) && tif->tif_nsubifd == 0)
+        tif->tif_flags &= ~TIFF_INSUBIFD;
+
+    /* Add or update this directory to the IFD list. */
+    if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, tif->tif_diroff))
+    {
+        TIFFErrorExtR(tif, module,
+                      "Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64
+                      ") might cause an IFD loop",
+                      tif->tif_curdir, tif->tif_diroff, tif->tif_diroff);
+    }
+
     if (imagedone)
     {
         TIFFFreeDirectory(tif);
         tif->tif_flags &= ~TIFF_DIRTYDIRECT;
         tif->tif_flags &= ~TIFF_DIRTYSTRIP;
         (*tif->tif_cleanup)(tif);
-        /*
-         * Reset directory-related state for subsequent
-         * directories.
-         */
+        /* Reset directory-related state for subsequent directories. */
         TIFFCreateDirectory(tif);
     }
+    else
+    {
+        /* IFD is only checkpointed to file (or a custom IFD like EXIF is
+         * written), thus set IFD data size written to file. */
+        tif->tif_dir.td_dirdatasize_read = tif->tif_dir.td_dirdatasize_write;
+    }
     return (1);
 bad:
     if (dir != NULL)
@@ -1401,11 +1532,6 @@
                                       TIFFDirEntry *dir, uint16_t tag,
                                       uint32_t count, char *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (
         TIFFWriteDirectoryTagCheckedAscii(tif, ndir, dir, tag, count, value));
 }
@@ -1414,11 +1540,6 @@
                                                TIFFDirEntry *dir, uint16_t tag,
                                                uint32_t count, uint8_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedUndefinedArray(tif, ndir, dir, tag,
                                                        count, value));
 }
@@ -1427,11 +1548,6 @@
                                           TIFFDirEntry *dir, uint16_t tag,
                                           uint32_t count, uint8_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedByteArray(tif, ndir, dir, tag, count,
                                                   value));
 }
@@ -1440,11 +1556,6 @@
                                            TIFFDirEntry *dir, uint16_t tag,
                                            uint32_t count, int8_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedSbyteArray(tif, ndir, dir, tag, count,
                                                    value));
 }
@@ -1453,11 +1564,6 @@
                                       TIFFDirEntry *dir, uint16_t tag,
                                       uint16_t value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, value));
 }
 
@@ -1465,11 +1571,6 @@
                                            TIFFDirEntry *dir, uint16_t tag,
                                            uint32_t count, uint16_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count,
                                                    value));
 }
@@ -1485,8 +1586,9 @@
     int o;
     if (dir == NULL)
     {
-        (*ndir)++;
-        return (1);
+        /* only evaluate IFD data size and inc. ndir */
+        return (TIFFWriteDirectoryTagCheckedShortArray(
+            tif, ndir, dir, tag, tif->tif_dir.td_samplesperpixel, NULL));
     }
     m = _TIFFmallocExt(tif, tif->tif_dir.td_samplesperpixel * sizeof(uint16_t));
     if (m == NULL)
@@ -1506,11 +1608,6 @@
                                             TIFFDirEntry *dir, uint16_t tag,
                                             uint32_t count, int16_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedSshortArray(tif, ndir, dir, tag, count,
                                                     value));
 }
@@ -1519,11 +1616,6 @@
                                      TIFFDirEntry *dir, uint16_t tag,
                                      uint32_t value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedLong(tif, ndir, dir, tag, value));
 }
 
@@ -1531,11 +1623,6 @@
                                           TIFFDirEntry *dir, uint16_t tag,
                                           uint32_t count, uint32_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count,
                                                   value));
 }
@@ -1544,11 +1631,6 @@
                                            TIFFDirEntry *dir, uint16_t tag,
                                            uint32_t count, int32_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count,
                                                    value));
 }
@@ -1572,8 +1654,9 @@
     /* is this just a counting pass? */
     if (dir == NULL)
     {
-        (*ndir)++;
-        return (1);
+        /* only evaluate IFD data size and inc. ndir */
+        return (TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag,
+                                                       count, value));
     }
 
     /* We always write Long8 for BigTIFF, no checking needed. */
@@ -1632,8 +1715,9 @@
     /* is this just a counting pass? */
     if (dir == NULL)
     {
-        (*ndir)++;
-        return (1);
+        /* only evaluate IFD data size and inc. ndir */
+        return (TIFFWriteDirectoryTagCheckedSlong8Array(tif, ndir, dir, tag,
+                                                        count, value));
     }
     /* We always write SLong8 for BigTIFF, no checking needed. */
     if (tif->tif_flags & TIFF_BIGTIFF)
@@ -1686,11 +1770,6 @@
                                          TIFFDirEntry *dir, uint16_t tag,
                                          double value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedRational(tif, ndir, dir, tag, value));
 }
 
@@ -1698,11 +1777,6 @@
                                               TIFFDirEntry *dir, uint16_t tag,
                                               uint32_t count, float *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedRationalArray(tif, ndir, dir, tag,
                                                       count, value));
 }
@@ -1711,11 +1785,6 @@
                                                TIFFDirEntry *dir, uint16_t tag,
                                                uint32_t count, float *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedSrationalArray(tif, ndir, dir, tag,
                                                        count, value));
 }
@@ -1727,11 +1796,6 @@
                                                     uint32_t count,
                                                     double *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedRationalDoubleArray(tif, ndir, dir, tag,
                                                             count, value));
 }
@@ -1742,11 +1806,6 @@
                                                      uint32_t count,
                                                      double *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedSrationalDoubleArray(
         tif, ndir, dir, tag, count, value));
 }
@@ -1755,11 +1814,6 @@
                                            TIFFDirEntry *dir, uint16_t tag,
                                            uint32_t count, float *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedFloatArray(tif, ndir, dir, tag, count,
                                                    value));
 }
@@ -1768,11 +1822,6 @@
                                             TIFFDirEntry *dir, uint16_t tag,
                                             uint32_t count, double *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedDoubleArray(tif, ndir, dir, tag, count,
                                                     value));
 }
@@ -1781,11 +1830,6 @@
                                          TIFFDirEntry *dir, uint16_t tag,
                                          uint32_t count, uint32_t *value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     return (TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count,
                                                  value));
 }
@@ -1794,11 +1838,6 @@
                                           TIFFDirEntry *dir, uint16_t tag,
                                           uint32_t value)
 {
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     if (value <= 0xFFFF)
         return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag,
                                                   (uint16_t)value));
@@ -1824,7 +1863,7 @@
              compression == COMPRESSION_WEBP || compression == COMPRESSION_JXL)
     {
         /* For a few select compression types, we assume that in the worst */
-        /* case the compressed size will be 10 times the uncompressed size */
+        /* case the compressed size will be 10 times the uncompressed size. */
         /* This is overly pessismistic ! */
         return strile_size >= uncompressed_threshold / 10;
     }
@@ -1856,15 +1895,16 @@
     int o;
     int write_aslong4;
 
-    /* is this just a counting pass? */
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
-
     if (tif->tif_dir.td_deferstrilearraywriting)
     {
+        if (dir == NULL)
+        {
+            /* This is just a counting pass to count IFD entries.
+             * For deferstrilearraywriting no extra bytes will be written
+             * into IFD space. */
+            (*ndir)++;
+            return 1;
+        }
         return TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_NOTYPE, 0, 0,
                                          NULL);
     }
@@ -1872,12 +1912,10 @@
     if (tif->tif_flags & TIFF_BIGTIFF)
     {
         int write_aslong8 = 1;
-        /* In the case of ByteCounts array, we may be able to write them on */
-        /* LONG if the strip/tilesize is not too big. */
-        /* Also do that for count > 1 in the case someone would want to create
-         */
-        /* a single-strip file with a growing height, in which case using */
-        /* LONG8 will be safer. */
+        /* In the case of ByteCounts array, we may be able to write them on LONG
+         * if the strip/tilesize is not too big. Also do that for count > 1 in
+         * the case someone would want to create a single-strip file with a
+         * growing height, in which case using LONG8 will be safer. */
         if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS)
         {
             write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif));
@@ -1989,13 +2027,6 @@
     uint32_t *q;
     int o;
 
-    /* is this just a counting pass? */
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
-
     /* We always write IFD8 for BigTIFF, no checking needed. */
     if (tif->tif_flags & TIFF_BIGTIFF)
         return TIFFWriteDirectoryTagCheckedIfd8Array(tif, ndir, dir, tag, count,
@@ -2032,6 +2063,26 @@
     return (o);
 }
 
+/*
+ * Auxiliary function to determine the IFD data size to be written to the file.
+ * The IFD data size is finally the size of the IFD tag entries plus the IFD
+ * data that is written directly after the IFD tag entries.
+ */
+static void EvaluateIFDdatasizeWrite(TIFF *tif, uint32_t count,
+                                     uint32_t typesize, uint32_t *ndir)
+{
+    uint64_t datalength = (uint64_t)count * typesize;
+    if (datalength > ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U))
+    {
+        /* LibTIFF increments write address to an even offset, thus datalength
+         * written is also incremented. */
+        if (datalength & 1)
+            datalength++;
+        tif->tif_dir.td_dirdatasize_write += datalength;
+    }
+    (*ndir)++;
+}
+
 static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir,
                                          TIFFDirEntry *dir)
 {
@@ -2039,12 +2090,13 @@
     uint32_t m;
     uint16_t *n;
     int o;
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     m = (1 << tif->tif_dir.td_bitspersample);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, 3 * m, sizeof(uint16_t), ndir);
+        return 1;
+    }
+
     n = _TIFFmallocExt(tif, 3 * m * sizeof(uint16_t));
     if (n == NULL)
     {
@@ -2068,11 +2120,6 @@
     uint16_t n;
     uint16_t *o;
     int p;
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     /* TIFFTAG_TRANSFERFUNCTION expects (1 or 3) pointer to arrays with
      *  (1 << BitsPerSample) * uint16_t values.
      */
@@ -2086,9 +2133,9 @@
     {
         if (tif->tif_dir.td_transferfunction[i] == NULL)
         {
-            TIFFWarningExtR(
-                tif, module,
-                "Too few TransferFunctions provided. Tag not written to file");
+            TIFFWarningExtR(tif, module,
+                            "Too few TransferFunctions provided. Tag "
+                            "not written to file");
             return (1); /* Not an error; only tag is not written. */
         }
     }
@@ -2108,6 +2155,12 @@
                          m * sizeof(uint16_t)))
             n = 1;
     }
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, n * m, 2, ndir);
+        return 1;
+    }
+
     o = _TIFFmallocExt(tif, n * m * sizeof(uint16_t));
     if (o == NULL)
     {
@@ -2136,11 +2189,6 @@
     int n;
     if (tif->tif_dir.td_nsubifd == 0)
         return (1);
-    if (dir == NULL)
-    {
-        (*ndir)++;
-        return (1);
-    }
     m = tif->tif_dataoff;
     if (!(tif->tif_flags & TIFF_BIGTIFF))
     {
@@ -2178,6 +2226,12 @@
         n = TIFFWriteDirectoryTagCheckedIfd8Array(
             tif, ndir, dir, TIFFTAG_SUBIFD, tif->tif_dir.td_nsubifd,
             tif->tif_dir.td_subifd);
+
+    if (dir == NULL)
+        /* Just have evaluated IFD data size and incremented ndir
+         * above in sub-functions. */
+        return (n);
+
     if (!n)
         return (0);
     /*
@@ -2202,6 +2256,11 @@
                                              uint32_t count, char *value)
 {
     assert(sizeof(char) == 1);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 1, ndir);
+        return 1;
+    }
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_ASCII, count,
                                       count, value));
 }
@@ -2213,6 +2272,11 @@
                                                       uint8_t *value)
 {
     assert(sizeof(uint8_t) == 1);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 1, ndir);
+        return 1;
+    }
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_UNDEFINED,
                                       count, count, value));
 }
@@ -2223,6 +2287,11 @@
                                                  uint8_t *value)
 {
     assert(sizeof(uint8_t) == 1);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 1, ndir);
+        return 1;
+    }
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_BYTE, count,
                                       count, value));
 }
@@ -2233,6 +2302,11 @@
                                                   int8_t *value)
 {
     assert(sizeof(int8_t) == 1);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 1, ndir);
+        return 1;
+    }
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SBYTE, count,
                                       count, value));
 }
@@ -2243,6 +2317,12 @@
 {
     uint16_t m;
     assert(sizeof(uint16_t) == 2);
+    if (dir == NULL)
+    {
+        /* No additional data to IFD data size just increment ndir. */
+        (*ndir)++;
+        return 1;
+    }
     m = value;
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabShort(&m);
@@ -2257,6 +2337,11 @@
 {
     assert(count < 0x80000000);
     assert(sizeof(uint16_t) == 2);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 2, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfShort(value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SHORT, count,
@@ -2270,6 +2355,11 @@
 {
     assert(count < 0x80000000);
     assert(sizeof(int16_t) == 2);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 2, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfShort((uint16_t *)value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SSHORT, count,
@@ -2282,6 +2372,12 @@
 {
     uint32_t m;
     assert(sizeof(uint32_t) == 4);
+    if (dir == NULL)
+    {
+        /* No additional data to IFD data size just increment ndir. */
+        (*ndir)++;
+        return 1;
+    }
     m = value;
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabLong(&m);
@@ -2296,6 +2392,11 @@
 {
     assert(count < 0x40000000);
     assert(sizeof(uint32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 4, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfLong(value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG, count,
@@ -2309,6 +2410,11 @@
 {
     assert(count < 0x40000000);
     assert(sizeof(int32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 4, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfLong((uint32_t *)value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG, count,
@@ -2328,6 +2434,11 @@
                       "LONG8 not allowed for ClassicTIFF");
         return (0);
     }
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 8, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfLong8(value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG8, count,
@@ -2347,6 +2458,11 @@
                       "SLONG8 not allowed for ClassicTIFF");
         return (0);
     }
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 8, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfLong8((uint64_t *)value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG8, count,
@@ -2370,16 +2486,17 @@
         TIFFErrorExtR(tif, module, "Not-a-number value is illegal");
         return 0;
     }
-    /*--Rational2Double: New function also used for non-custom rational tags.
-     *  However, could be omitted here, because
-     * TIFFWriteDirectoryTagCheckedRational() is not used by code for custom
-     * tags, only by code for named-tiff-tags like FIELD_RESOLUTION and
-     * FIELD_POSITION */
-    else
+
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
     {
-        DoubleToRational(value, &m[0], &m[1]);
+        tif->tif_dir.td_dirdatasize_write +=
+            (tif->tif_flags & TIFF_BIGTIFF) ? 0 : 0x8U;
+        (*ndir)++;
+        return 1;
     }
 
+    DoubleToRational(value, &m[0], &m[1]);
+
     if (tif->tif_flags & TIFF_SWAB)
     {
         TIFFSwabLong(&m[0]);
@@ -2402,6 +2519,11 @@
     uint32_t nc;
     int o;
     assert(sizeof(uint32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(uint32_t), ndir);
+        return 1;
+    }
     m = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t));
     if (m == NULL)
     {
@@ -2433,6 +2555,11 @@
     uint32_t nc;
     int o;
     assert(sizeof(int32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(int32_t), ndir);
+        return 1;
+    }
     m = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t));
     if (m == NULL)
     {
@@ -2465,6 +2592,11 @@
     uint32_t nc;
     int o;
     assert(sizeof(uint32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(uint32_t), ndir);
+        return 1;
+    }
     m = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t));
     if (m == NULL)
     {
@@ -2495,6 +2627,11 @@
     uint32_t nc;
     int o;
     assert(sizeof(int32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(int32_t), ndir);
+        return 1;
+    }
     m = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t));
     if (m == NULL)
     {
@@ -2816,6 +2953,11 @@
 {
     assert(count < 0x40000000);
     assert(sizeof(float) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 4, ndir);
+        return 1;
+    }
     TIFFCvtNativeToIEEEFloat(tif, count, &value);
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfFloat(value, count);
@@ -2830,6 +2972,11 @@
 {
     assert(count < 0x20000000);
     assert(sizeof(double) == 8);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 8, ndir);
+        return 1;
+    }
     TIFFCvtNativeToIEEEDouble(tif, count, &value);
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfDouble(value, count);
@@ -2843,6 +2990,11 @@
 {
     assert(count < 0x40000000);
     assert(sizeof(uint32_t) == 4);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 4, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfLong(value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD, count,
@@ -2857,6 +3009,11 @@
     assert(count < 0x20000000);
     assert(sizeof(uint64_t) == 8);
     assert(tif->tif_flags & TIFF_BIGTIFF);
+    if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */
+    {
+        EvaluateIFDdatasizeWrite(tif, count, 8, ndir);
+        return 1;
+    }
     if (tif->tif_flags & TIFF_SWAB)
         TIFFSwabArrayOfLong8(value, count);
     return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD8, count,
@@ -2973,15 +3130,15 @@
                               "Error writing SubIFD directory link");
                 return (0);
             }
+
             /*
              * Advance to the next SubIFD or, if this is
-             * the last one configured, revert back to the
-             * normal directory linkage.
+             * the last one configured, reverting back to the
+             * normal directory linkage is done in TIFFWriteDirectorySec()
+             * by tif->tif_flags &= ~TIFF_INSUBIFD;.
              */
             if (--tif->tif_nsubifd)
                 tif->tif_subifdoff += 4;
-            else
-                tif->tif_flags &= ~TIFF_INSUBIFD;
             return (1);
         }
         else
@@ -2997,19 +3154,23 @@
                               "Error writing SubIFD directory link");
                 return (0);
             }
+
             /*
              * Advance to the next SubIFD or, if this is
-             * the last one configured, revert back to the
-             * normal directory linkage.
+             * the last one configured, reverting back to the
+             * normal directory linkage is done in TIFFWriteDirectorySec()
+             * by tif->tif_flags &= ~TIFF_INSUBIFD;.
              */
             if (--tif->tif_nsubifd)
                 tif->tif_subifdoff += 8;
-            else
-                tif->tif_flags &= ~TIFF_INSUBIFD;
             return (1);
         }
     }
 
+    /*
+     * Handle main-IFDs
+     */
+    tdir_t ndir = 1; /* count current number of main-IFDs */
     if (!(tif->tif_flags & TIFF_BIGTIFF))
     {
         uint32_t m;
@@ -3030,18 +3191,26 @@
                 TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
                 return (0);
             }
+            if (!tif->tif_dir.td_iswrittentofile)
+                tif->tif_curdircount = 0;
             return (1);
         }
         /*
          * Not the first directory, search to the last and append.
          */
-        if (tif->tif_lastdiroff != 0)
+        tdir_t dirn = 0;
+        if (tif->tif_lastdiroff != 0 &&
+            _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn))
         {
+            /* Start searching from the lastely written IFD. Thus get its IFD
+             * number. */
             nextdir = (uint32_t)tif->tif_lastdiroff;
+            ndir = dirn + 1;
         }
         else
         {
             nextdir = tif->tif_header.classic.tiff_diroff;
+            ndir = 1; /* start searching from the first IFD */
         }
 
         while (1)
@@ -3076,10 +3245,12 @@
                 break;
             }
             nextdir = nextnextdir;
+            ndir++;
         }
     }
     else
     {
+        /*- BigTIFF -*/
         uint64_t m;
         uint64_t nextdir;
         m = tif->tif_diroff;
@@ -3098,18 +3269,26 @@
                 TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
                 return (0);
             }
+            if (!tif->tif_dir.td_iswrittentofile)
+                tif->tif_curdircount = 0;
             return (1);
         }
         /*
          * Not the first directory, search to the last and append.
          */
-        if (tif->tif_lastdiroff != 0)
+        tdir_t dirn = 0;
+        if (tif->tif_lastdiroff != 0 &&
+            _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn))
         {
+            /* Start searching from the lastely written IFD. Thus get its IFD
+             * number. */
             nextdir = tif->tif_lastdiroff;
+            ndir = dirn + 1;
         }
         else
         {
             nextdir = tif->tif_header.big.tiff_diroff;
+            ndir = 1; /* start searching from the first IFD */
         }
         while (1)
         {
@@ -3126,9 +3305,9 @@
                 TIFFSwabLong8(&dircount64);
             if (dircount64 > 0xFFFF)
             {
-                TIFFErrorExtR(
-                    tif, module,
-                    "Sanity check on tag count failed, likely corrupt TIFF");
+                TIFFErrorExtR(tif, module,
+                              "Sanity check on tag count failed, "
+                              "likely corrupt TIFF");
                 return (0);
             }
             dircount = (uint16_t)dircount64;
@@ -3152,8 +3331,20 @@
                 break;
             }
             nextdir = nextnextdir;
+            ndir++;
         }
     }
+    /* Offset of next IFD is written to file.
+     * Update number of main-IFDs in file.
+     * However, tif_curdircount shall count only newly written main-IFDs with
+     * entries and not only number of linked offsets! Thus, tif_curdircount is
+     * incremented at the end of TIFFWriteDirectorySec().
+     * TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs'
+     * 0 means 'empty file opened for writing, but no IFD written yet' */
+    if (!tif->tif_dir.td_iswrittentofile && !(tif->tif_flags & TIFF_INSUBIFD))
+    {
+        tif->tif_curdircount = ndir;
+    }
     return (1);
 }
 
@@ -3197,9 +3388,9 @@
     /* -------------------------------------------------------------------- */
     if (isMapped(tif))
     {
-        TIFFErrorExtR(
-            tif, module,
-            "Memory mapped files not currently supported for this operation.");
+        TIFFErrorExtR(tif, module,
+                      "Memory mapped files not currently supported for "
+                      "this operation.");
         return 0;
     }
 
diff --git a/third_party/libtiff/tif_fax3.c b/third_party/libtiff/tif_fax3.c
index a3c645c..01a7847 100644
--- a/third_party/libtiff/tif_fax3.c
+++ b/third_party/libtiff/tif_fax3.c
@@ -41,6 +41,14 @@
 #include "t4.h"
 #include <stdio.h>
 
+#ifndef EOF_REACHED_COUNT_THRESHOLD
+/* Arbitrary threshold to avoid corrupted single-strip files with extremely
+ * large imageheight to cause apparently endless looping, such as in
+ * https://gitlab.com/libtiff/libtiff/-/issues/583
+ */
+#define EOF_REACHED_COUNT_THRESHOLD 8192
+#endif
+
 /*
  * Compression+decompression state blocks are
  * derived from this ``base state'' block.
@@ -77,6 +85,8 @@
     uint32_t data;               /* current i/o byte/word */
     int bit;                     /* current i/o bit in byte */
     int EOLcnt;                  /* count of EOL codes recognized */
+    int eofReachedCount;         /* number of times decode has been called with
+                                    EOF already reached */
     TIFFFaxFillFunc fill;        /* fill routine */
     uint32_t *runs;              /* b&w runs for current/previous row */
     uint32_t nruns;              /* size of the refruns / curruns arrays */
@@ -120,6 +130,7 @@
     int EOLcnt;                               /* # EOL codes recognized */     \
     const unsigned char *bitmap = sp->bitmap; /* input data bit reverser */    \
     const TIFFFaxTabEnt *TabEnt
+
 #define DECLARE_STATE_2D(tif, sp, mod)                                         \
     DECLARE_STATE(tif, sp, mod);                                               \
     int b1; /* next change on prev line */                                     \
@@ -162,6 +173,7 @@
     sp->bit = 0; /* force initial read */
     sp->data = 0;
     sp->EOLcnt = 0; /* force initial scan for EOL */
+    sp->eofReachedCount = 0;
     /*
      * Decoder assumes lsb-to-msb bit order.  Note that we select
      * this here rather than in Fax3SetupState so that viewers can
@@ -232,7 +244,12 @@
                     line, isTiled(tif) ? "tile" : "strip",
                     (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0);
 }
-#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0)
+#define prematureEOF(a0)                                                       \
+    do                                                                         \
+    {                                                                          \
+        Fax3PrematureEOF(module, tif, sp->line, a0);                           \
+        ++sp->eofReachedCount;                                                 \
+    } while (0)
 
 #define Nop
 
@@ -252,6 +269,14 @@
         TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
         return (-1);
     }
+    if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD)
+    {
+        TIFFErrorExtR(
+            tif, module,
+            "End of file has already been reached %d times within that strip",
+            sp->eofReachedCount);
+        return (-1);
+    }
     CACHE_STATE(tif, sp);
     thisrun = sp->curruns;
     while (occ > 0)
@@ -302,6 +327,14 @@
         TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
         return (-1);
     }
+    if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD)
+    {
+        TIFFErrorExtR(
+            tif, module,
+            "End of file has already been reached %d times within that strip",
+            sp->eofReachedCount);
+        return (-1);
+    }
     CACHE_STATE(tif, sp);
     while (occ > 0)
     {
@@ -536,7 +569,11 @@
 
       TIFFroundup and TIFFSafeMultiply return zero on integer overflow
     */
-    dsp->runs = (uint32_t *)NULL;
+    if (dsp->runs != NULL)
+    {
+        _TIFFfreeExt(tif, dsp->runs);
+        dsp->runs = (uint32_t *)NULL;
+    }
     dsp->nruns = TIFFroundup_32(rowpixels + 1, 32);
     if (needsRefLine)
     {
@@ -578,6 +615,10 @@
          * is referenced.  The reference line must
          * be initialized to be ``white'' (done elsewhere).
          */
+        if (esp->refline != NULL)
+        {
+            _TIFFfreeExt(tif, esp->refline);
+        }
         esp->refline = (unsigned char *)_TIFFmallocExt(tif, rowbytes);
         if (esp->refline == NULL)
         {
@@ -1514,7 +1555,16 @@
         TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
         return (-1);
     }
+    if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD)
+    {
+        TIFFErrorExtR(
+            tif, module,
+            "End of file has already been reached %d times within that strip",
+            sp->eofReachedCount);
+        return (-1);
+    }
     CACHE_STATE(tif, sp);
+    int start = sp->line;
     while (occ > 0)
     {
         a0 = 0;
@@ -1563,7 +1613,9 @@
         }
         (*sp->fill)(buf, thisrun, pa, lastx);
         UNCACHE_STATE(tif, sp);
-        return (sp->line ? 1 : -1); /* don't error on badly-terminated strips */
+        return (sp->line != start
+                    ? 1
+                    : -1); /* don't error on badly-terminated strips */
     }
     UNCACHE_STATE(tif, sp);
     return (1);
diff --git a/third_party/libtiff/tif_getimage.c b/third_party/libtiff/tif_getimage.c
index f5a05e5..3ee0626 100644
--- a/third_party/libtiff/tif_getimage.c
+++ b/third_party/libtiff/tif_getimage.c
@@ -761,6 +761,12 @@
         toskew = -(int32_t)(tw - w);
     }
 
+    if (tw == 0 || th == 0)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero");
+        return (0);
+    }
+
     /*
      *	Leftmost tile is clipped on left side if col_offset > 0.
      */
@@ -936,6 +942,12 @@
             break;
     }
 
+    if (tw == 0 || th == 0)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero");
+        return (0);
+    }
+
     /*
      *	Leftmost tile is clipped on left side if col_offset > 0.
      */
@@ -1118,6 +1130,11 @@
     }
 
     TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+    if (rowsperstrip == 0)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
+        return (0);
+    }
 
     scanline = TIFFScanlineSize(tif);
     fromskew = (w < imagewidth ? imagewidth - w : 0);
@@ -1242,6 +1259,12 @@
     }
 
     TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+    if (rowsperstrip == 0)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
+        return (0);
+    }
+
     scanline = TIFFScanlineSize(tif);
     fromskew = (w < imagewidth ? imagewidth - w : 0);
     for (row = 0; row < h; row += nrow)
@@ -3239,6 +3262,13 @@
     }
 
     TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+
+    if (rowsperstrip == 0)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
+        return (0);
+    }
+
     if ((row % rowsperstrip) != 0)
     {
         TIFFErrorExtR(
@@ -3250,6 +3280,13 @@
     if (TIFFRGBAImageOK(tif, emsg) &&
         TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg))
     {
+        if (row >= img.height)
+        {
+            TIFFErrorExtR(tif, TIFFFileName(tif),
+                          "Invalid row passed to TIFFReadRGBAStrip().");
+            TIFFRGBAImageEnd(&img);
+            return (0);
+        }
 
         img.row_offset = row;
         img.col_offset = 0;
@@ -3308,6 +3345,13 @@
 
     TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize);
     TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize);
+    if (tile_xsize == 0 || tile_ysize == 0)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif),
+                      "tile_xsize or tile_ysize is zero");
+        return (0);
+    }
+
     if ((col % tile_xsize) != 0 || (row % tile_ysize) != 0)
     {
         TIFFErrorExtR(tif, TIFFFileName(tif),
@@ -3327,6 +3371,14 @@
         return (0);
     }
 
+    if (col >= img.width || row >= img.height)
+    {
+        TIFFErrorExtR(tif, TIFFFileName(tif),
+                      "Invalid row/col passed to TIFFReadRGBATile().");
+        TIFFRGBAImageEnd(&img);
+        return (0);
+    }
+
     /*
      * The TIFFRGBAImageGet() function doesn't allow us to get off the
      * edge of the image, even to fill an otherwise valid tile.  So we
diff --git a/third_party/libtiff/tif_hash_set.c b/third_party/libtiff/tif_hash_set.c
index cec22ab..9be488e 100644
--- a/third_party/libtiff/tif_hash_set.c
+++ b/third_party/libtiff/tif_hash_set.c
@@ -146,7 +146,7 @@
     set->fnEqualFunc = fnEqualFunc ? fnEqualFunc : TIFFHashSetEqualPointer;
     set->fnFreeEltFunc = fnFreeEltFunc;
     set->nSize = 0;
-    set->tabList = (TIFFList **)(calloc(sizeof(TIFFList *), 53));
+    set->tabList = (TIFFList **)(calloc(53, sizeof(TIFFList *)));
     if (set->tabList == NULL)
     {
         free(set);
@@ -367,7 +367,7 @@
 {
     int nNewAllocatedSize = anPrimes[set->nIndiceAllocatedSize];
     TIFFList **newTabList =
-        (TIFFList **)(calloc(sizeof(TIFFList *), nNewAllocatedSize));
+        (TIFFList **)(calloc(nNewAllocatedSize, sizeof(TIFFList *)));
     if (newTabList == NULL)
         return false;
 #ifdef HASH_DEBUG
diff --git a/third_party/libtiff/tif_jpeg.c b/third_party/libtiff/tif_jpeg.c
index a7dbde7..8eb2f74 100644
--- a/third_party/libtiff/tif_jpeg.c
+++ b/third_party/libtiff/tif_jpeg.c
@@ -73,43 +73,6 @@
                       int scheme, int is_encode);
 int TIFFJPEGIsFullStripRequired_12(TIFF *tif);
 
-/* We undefine FAR to avoid conflict with JPEG definition */
-
-#ifdef FAR
-#undef FAR
-#endif
-
-/*
-  Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
-  not defined.  Unfortunately, the MinGW and Borland compilers include
-  a typedef for INT32, which causes a conflict.  MSVC does not include
-  a conflicting typedef given the headers which are included.
-*/
-#if defined(__BORLANDC__) || defined(__MINGW32__)
-#define XMD_H 1
-#endif
-
-/*
-   The windows RPCNDR.H file defines boolean, but defines it with the
-   unsigned char size.  You should compile JPEG library using appropriate
-   definitions in jconfig.h header, but many users compile library in wrong
-   way. That causes errors of the following type:
-
-   "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432,
-   caller expects 464"
-
-   For such users we will fix the problem here. See install.doc file from
-   the JPEG library distribution for details.
-*/
-
-/* Define "boolean" as unsigned char, not int, per Windows custom. */
-#if defined(__WIN32__) && !defined(__MINGW32__)
-#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
-typedef unsigned char boolean;
-#endif
-#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
-#endif
-
 #if defined(USE_SYSTEM_LIBJPEG)
 #include <jerror.h>
 #include <jpeglib.h>
@@ -133,18 +96,18 @@
  * 16bit value?
  */
 
-/* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which
+/* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 3.0 which
  * adds a dual-mode 8/12 bit API in the same library.
  */
 
 #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12)
 #define JPEG_DUAL_MODE_8_12
 /* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo
- * >= 2.2 Cf
+ * >= 3.0 Cf
  * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b
  */
 #undef BITS_IN_JSAMPLE
-/* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */
+/* libjpeg-turbo >= 3.0 adds J12xxxx datatypes for the 12-bit mode. */
 #if defined(FROM_TIF_JPEG_12)
 #define BITS_IN_JSAMPLE 12
 #define TIFF_JSAMPLE J12SAMPLE
@@ -190,9 +153,20 @@
 #define LONGJMP(jbuf, code) longjmp(jbuf, code)
 #define JMP_BUF jmp_buf
 
+#ifndef TIFF_jpeg_destination_mgr_defined
+#define TIFF_jpeg_destination_mgr_defined
 typedef struct jpeg_destination_mgr jpeg_destination_mgr;
+#endif
+
+#ifndef TIFF_jpeg_source_mgr_defined
+#define TIFF_jpeg_source_mgr_defined
 typedef struct jpeg_source_mgr jpeg_source_mgr;
+#endif
+
+#ifndef TIFF_jpeg_error_mgr_defined
+#define TIFF_jpeg_error_mgr_defined
 typedef struct jpeg_error_mgr jpeg_error_mgr;
+#endif
 
 /*
  * State block for each open TIFF file using
@@ -1249,6 +1223,12 @@
          * For PC 2, scale down the expected strip/tile size
          * to match a downsampled component
          */
+        if (sp->h_sampling == 0 || sp->v_sampling == 0)
+        {
+            TIFFErrorExtR(tif, module,
+                          "JPEG horizontal or vertical sampling is zero");
+            return (0);
+        }
         segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
         segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
     }
@@ -1479,7 +1459,10 @@
     sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc;
 
     if (sp->bytesperline == 0)
+    {
+        memset(buf, 0, (size_t)cc);
         return 0;
+    }
 
     nrows = cc / sp->bytesperline;
     if (cc % sp->bytesperline)
@@ -1500,7 +1483,10 @@
             JSAMPROW bufptr = (JSAMPROW)buf;
 
             if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1)
+            {
+                memset(buf, 0, (size_t)cc);
                 return (0);
+            }
 
             ++tif->tif_row;
             buf += sp->bytesperline;
@@ -1534,7 +1520,10 @@
     sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc;
 
     if (sp->bytesperline == 0)
+    {
+        memset(buf, 0, (size_t)cc);
         return 0;
+    }
 
     nrows = cc / sp->bytesperline;
     if (cc % sp->bytesperline)
@@ -1570,7 +1559,10 @@
                  * for 12bit data, which we need to repack.
                  */
                 if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1)
+                {
+                    memset(buf, 0, (size_t)cc);
                     return (0);
+                }
 
                 if (sp->cinfo.d.data_precision == 12)
                 {
@@ -2198,6 +2190,12 @@
         /* for PC 2, scale down the strip/tile size
          * to match a downsampled component
          */
+        if (sp->h_sampling == 0 || sp->v_sampling == 0)
+        {
+            TIFFErrorExtR(tif, module,
+                          "JPEG horizontal or vertical sampling is zero");
+            return (0);
+        }
         segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
         segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
     }
diff --git a/third_party/libtiff/tif_luv.c b/third_party/libtiff/tif_luv.c
index 021756d..d196535 100644
--- a/third_party/libtiff/tif_luv.c
+++ b/third_party/libtiff/tif_luv.c
@@ -951,7 +951,8 @@
     int
     uv_encode(double u, double v, int em) /* encode (u',v') coordinates */
 {
-    register int vi, ui;
+    unsigned int vi;
+    int ui;
 
     /* check for NaN */
     if (u != u || v != v)
@@ -980,8 +981,9 @@
     int
     uv_decode(double *up, double *vp, int c) /* decode (u',v') index */
 {
-    int upper, lower;
-    register int ui, vi;
+    unsigned int upper, lower;
+    int ui;
+    unsigned int vi;
 
     if (c < 0 || c >= UV_NDIVS)
         return (-1);
diff --git a/third_party/libtiff/tif_lzw.c b/third_party/libtiff/tif_lzw.c
index d631fa1..4baf78e 100644
--- a/third_party/libtiff/tif_lzw.c
+++ b/third_party/libtiff/tif_lzw.c
@@ -161,8 +161,8 @@
 } LZWCodecState;
 
 #define LZWState(tif) ((LZWBaseState *)(tif)->tif_data)
-#define DecoderState(tif) ((LZWCodecState *)LZWState(tif))
-#define EncoderState(tif) ((LZWCodecState *)LZWState(tif))
+#define LZWDecoderState(tif) ((LZWCodecState *)LZWState(tif))
+#define LZWEncoderState(tif) ((LZWCodecState *)LZWState(tif))
 
 static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s);
 #ifdef LZW_COMPAT
@@ -183,7 +183,7 @@
 static int LZWSetupDecode(TIFF *tif)
 {
     static const char module[] = "LZWSetupDecode";
-    LZWCodecState *sp = DecoderState(tif);
+    LZWCodecState *sp = LZWDecoderState(tif);
     int code;
 
     if (sp == NULL)
@@ -199,7 +199,7 @@
             return (0);
         }
 
-        sp = DecoderState(tif);
+        sp = LZWDecoderState(tif);
         sp->dec_codetab = NULL;
         sp->dec_decode = NULL;
 
@@ -245,7 +245,7 @@
 static int LZWPreDecode(TIFF *tif, uint16_t s)
 {
     static const char module[] = "LZWPreDecode";
-    LZWCodecState *sp = DecoderState(tif);
+    LZWCodecState *sp = LZWDecoderState(tif);
 
     (void)s;
     assert(sp != NULL);
@@ -329,10 +329,7 @@
 #ifdef WORDS_BIGENDIAN
 #define GetNextData(nextdata, bp) memcpy(&nextdata, bp, sizeof(nextdata))
 #elif SIZEOF_WORDTYPE == 8
-#if defined(__GNUC__) && defined(__x86_64__)
-#define GetNextData(nextdata, bp)                                              \
-    nextdata = __builtin_bswap64(*(uint64_t *)(bp))
-#elif defined(_M_X64)
+#if defined(_M_X64)
 #define GetNextData(nextdata, bp) nextdata = _byteswap_uint64(*(uint64_t *)(bp))
 #elif defined(__GNUC__)
 #define GetNextData(nextdata, bp)                                              \
@@ -346,10 +343,7 @@
                (((uint64_t)bp[6]) << 8) | (((uint64_t)bp[7]))
 #endif
 #elif SIZEOF_WORDTYPE == 4
-#if defined(__GNUC__) && defined(__i386__)
-#define GetNextData(nextdata, bp)                                              \
-    nextdata = __builtin_bswap32(*(uint32_t *)(bp))
-#elif defined(_M_X86)
+#if defined(_M_X86)
 #define GetNextData(nextdata, bp)                                              \
     nextdata = _byteswap_ulong(*(unsigned long *)(bp))
 #elif defined(__GNUC__)
@@ -409,7 +403,7 @@
 static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s)
 {
     static const char module[] = "LZWDecode";
-    LZWCodecState *sp = DecoderState(tif);
+    LZWCodecState *sp = LZWDecoderState(tif);
     uint8_t *op = (uint8_t *)op0;
     tmsize_t occ = occ0;
     uint8_t *bp;
@@ -423,6 +417,7 @@
 
     if (sp->read_error)
     {
+        memset(op, 0, (size_t)occ);
         TIFFErrorExtR(tif, module,
                       "LZWDecode: Scanline %" PRIu32 " cannot be read due to "
                       "previous error",
@@ -737,6 +732,7 @@
 
     if (occ > 0)
     {
+        memset(op, 0, (size_t)occ);
         TIFFErrorExtR(tif, module,
                       "Not enough data at scanline %" PRIu32 " (short %" PRIu64
                       " bytes)",
@@ -746,12 +742,14 @@
     return (1);
 
 no_eoi:
+    memset(op, 0, (size_t)occ);
     sp->read_error = 1;
     TIFFErrorExtR(tif, module,
                   "LZWDecode: Strip %" PRIu32 " not terminated with EOI code",
                   tif->tif_curstrip);
     return 0;
 error_code:
+    memset(op, 0, (size_t)occ);
     sp->read_error = 1;
     TIFFErrorExtR(tif, tif->tif_name, "Using code not yet in table");
     return 0;
@@ -800,7 +798,7 @@
 static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s)
 {
     static const char module[] = "LZWDecodeCompat";
-    LZWCodecState *sp = DecoderState(tif);
+    LZWCodecState *sp = LZWDecoderState(tif);
     uint8_t *op = (uint8_t *)op0;
     tmsize_t occ = occ0;
     uint8_t *tp;
@@ -1026,7 +1024,7 @@
 static int LZWSetupEncode(TIFF *tif)
 {
     static const char module[] = "LZWSetupEncode";
-    LZWCodecState *sp = EncoderState(tif);
+    LZWCodecState *sp = LZWEncoderState(tif);
 
     assert(sp != NULL);
     sp->enc_hashtab = (hash_t *)_TIFFmallocExt(tif, HSIZE * sizeof(hash_t));
@@ -1043,7 +1041,7 @@
  */
 static int LZWPreEncode(TIFF *tif, uint16_t s)
 {
-    LZWCodecState *sp = EncoderState(tif);
+    LZWCodecState *sp = LZWEncoderState(tif);
 
     (void)s;
     assert(sp != NULL);
@@ -1114,7 +1112,7 @@
  */
 static int LZWEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
 {
-    register LZWCodecState *sp = EncoderState(tif);
+    register LZWCodecState *sp = LZWEncoderState(tif);
     register long fcode;
     register hash_t *hp;
     register int h, c;
@@ -1299,7 +1297,7 @@
  */
 static int LZWPostEncode(TIFF *tif)
 {
-    register LZWCodecState *sp = EncoderState(tif);
+    register LZWCodecState *sp = LZWEncoderState(tif);
     uint8_t *op = tif->tif_rawcp;
     long nextbits = sp->lzw_nextbits;
     WordType nextdata = sp->lzw_nextdata;
@@ -1381,11 +1379,11 @@
 
     assert(tif->tif_data != 0);
 
-    if (DecoderState(tif)->dec_codetab)
-        _TIFFfreeExt(tif, DecoderState(tif)->dec_codetab);
+    if (LZWDecoderState(tif)->dec_codetab)
+        _TIFFfreeExt(tif, LZWDecoderState(tif)->dec_codetab);
 
-    if (EncoderState(tif)->enc_hashtab)
-        _TIFFfreeExt(tif, EncoderState(tif)->enc_hashtab);
+    if (LZWEncoderState(tif)->enc_hashtab)
+        _TIFFfreeExt(tif, LZWEncoderState(tif)->enc_hashtab);
 
     _TIFFfreeExt(tif, tif->tif_data);
     tif->tif_data = NULL;
@@ -1404,9 +1402,9 @@
     tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZWCodecState));
     if (tif->tif_data == NULL)
         goto bad;
-    DecoderState(tif)->dec_codetab = NULL;
-    DecoderState(tif)->dec_decode = NULL;
-    EncoderState(tif)->enc_hashtab = NULL;
+    LZWDecoderState(tif)->dec_codetab = NULL;
+    LZWDecoderState(tif)->dec_decode = NULL;
+    LZWEncoderState(tif)->enc_hashtab = NULL;
     LZWState(tif)->rw_mode = tif->tif_mode;
 
     /*
diff --git a/third_party/libtiff/tif_open.c b/third_party/libtiff/tif_open.c
index 23fcf81..59a07be 100644
--- a/third_party/libtiff/tif_open.c
+++ b/third_party/libtiff/tif_open.c
@@ -25,7 +25,13 @@
 /*
  * TIFF Library.
  */
+
+#ifdef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
+#undef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
+#endif
+
 #include "tiffiop.h"
+#include <assert.h>
 #include <limits.h>
 
 /*
@@ -81,8 +87,9 @@
 void TIFFOpenOptionsFree(TIFFOpenOptions *opts) { _TIFFfree(opts); }
 
 /** Define a limit in bytes for a single memory allocation done by libtiff.
- *  If max_single_mem_alloc is set to 0, no other limit that the underlying
- *  _TIFFmalloc() will be applied, which is the default.
+ *  If max_single_mem_alloc is set to 0, which is the default, no other limit
+ *  that the underlying _TIFFmalloc() or
+ *  TIFFOpenOptionsSetMaxCumulatedMemAlloc() will be applied.
  */
 void TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts,
                                          tmsize_t max_single_mem_alloc)
@@ -90,6 +97,18 @@
     opts->max_single_mem_alloc = max_single_mem_alloc;
 }
 
+/** Define a limit in bytes for the cumulated memory allocations done by libtiff
+ *  on a given TIFF handle.
+ *  If max_cumulated_mem_alloc is set to 0, which is the default, no other limit
+ *  that the underlying _TIFFmalloc() or
+ *  TIFFOpenOptionsSetMaxSingleMemAlloc() will be applied.
+ */
+void TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts,
+                                            tmsize_t max_cumulated_mem_alloc)
+{
+    opts->max_cumulated_mem_alloc = max_cumulated_mem_alloc;
+}
+
 void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts,
                                         TIFFErrorHandlerExtR handler,
                                         void *errorhandler_user_data)
@@ -117,6 +136,30 @@
                   (uint64_t)s, (uint64_t)tif->tif_max_single_mem_alloc);
 }
 
+static void _TIFFEmitErrorAboveMaxCumulatedMemAlloc(TIFF *tif,
+                                                    const char *pszFunction,
+                                                    tmsize_t s)
+{
+    TIFFErrorExtR(tif, pszFunction,
+                  "Cumulated memory allocation of %" PRIu64 " + %" PRIu64
+                  " bytes is beyond the %" PRIu64
+                  " cumulated byte limit defined in open options",
+                  (uint64_t)tif->tif_cur_cumulated_mem_alloc, (uint64_t)s,
+                  (uint64_t)tif->tif_max_cumulated_mem_alloc);
+}
+
+/* When allocating memory, we write at the beginning of the buffer it size.
+ * This allows us to keep track of the total memory allocated when we
+ * malloc/calloc/realloc and free. In theory we need just SIZEOF_SIZE_T bytes
+ * for that, but on x86_64, allocations of more than 16 bytes are aligned on
+ * 16 bytes. Hence using 2 * SIZEOF_SIZE_T.
+ * It is critical that _TIFFmallocExt/_TIFFcallocExt/_TIFFreallocExt are
+ * paired with _TIFFfreeExt.
+ * CMakeLists.txt defines TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS, which in
+ * turn disables the definition of the non Ext version in tiffio.h
+ */
+#define LEADING_AREA_TO_STORE_ALLOC_SIZE (2 * SIZEOF_SIZE_T)
+
 /** malloc() version that takes into account memory-specific open options */
 void *_TIFFmallocExt(TIFF *tif, tmsize_t s)
 {
@@ -126,16 +169,32 @@
         _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFmallocExt", s);
         return NULL;
     }
+    if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
+    {
+        if (s > tif->tif_max_cumulated_mem_alloc -
+                    tif->tif_cur_cumulated_mem_alloc ||
+            s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE)
+        {
+            _TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFmallocExt", s);
+            return NULL;
+        }
+        void *ptr = _TIFFmalloc(LEADING_AREA_TO_STORE_ALLOC_SIZE + s);
+        if (!ptr)
+            return NULL;
+        tif->tif_cur_cumulated_mem_alloc += s;
+        memcpy(ptr, &s, sizeof(s));
+        return (char *)ptr + LEADING_AREA_TO_STORE_ALLOC_SIZE;
+    }
     return _TIFFmalloc(s);
 }
 
 /** calloc() version that takes into account memory-specific open options */
 void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz)
 {
+    if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz)
+        return NULL;
     if (tif != NULL && tif->tif_max_single_mem_alloc > 0)
     {
-        if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz)
-            return NULL;
         if (nmemb * siz > tif->tif_max_single_mem_alloc)
         {
             _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFcallocExt",
@@ -143,6 +202,23 @@
             return NULL;
         }
     }
+    if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
+    {
+        const tmsize_t s = nmemb * siz;
+        if (s > tif->tif_max_cumulated_mem_alloc -
+                    tif->tif_cur_cumulated_mem_alloc ||
+            s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE)
+        {
+            _TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFcallocExt", s);
+            return NULL;
+        }
+        void *ptr = _TIFFcalloc(LEADING_AREA_TO_STORE_ALLOC_SIZE + s, 1);
+        if (!ptr)
+            return NULL;
+        tif->tif_cur_cumulated_mem_alloc += s;
+        memcpy(ptr, &s, sizeof(s));
+        return (char *)ptr + LEADING_AREA_TO_STORE_ALLOC_SIZE;
+    }
     return _TIFFcalloc(nmemb, siz);
 }
 
@@ -155,13 +231,49 @@
         _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFreallocExt", s);
         return NULL;
     }
+    if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
+    {
+        void *oldPtr = p;
+        tmsize_t oldSize = 0;
+        if (p)
+        {
+            oldPtr = (char *)p - LEADING_AREA_TO_STORE_ALLOC_SIZE;
+            memcpy(&oldSize, oldPtr, sizeof(oldSize));
+            assert(oldSize <= tif->tif_cur_cumulated_mem_alloc);
+        }
+        if (s > oldSize &&
+            (s > tif->tif_max_cumulated_mem_alloc -
+                     (tif->tif_cur_cumulated_mem_alloc - oldSize) ||
+             s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE))
+        {
+            _TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFreallocExt",
+                                                    s - oldSize);
+            return NULL;
+        }
+        void *newPtr =
+            _TIFFrealloc(oldPtr, LEADING_AREA_TO_STORE_ALLOC_SIZE + s);
+        if (newPtr == NULL)
+            return NULL;
+        tif->tif_cur_cumulated_mem_alloc -= oldSize;
+        tif->tif_cur_cumulated_mem_alloc += s;
+        memcpy(newPtr, &s, sizeof(s));
+        return (char *)newPtr + LEADING_AREA_TO_STORE_ALLOC_SIZE;
+    }
     return _TIFFrealloc(p, s);
 }
 
 /** free() version that takes into account memory-specific open options */
 void _TIFFfreeExt(TIFF *tif, void *p)
 {
-    (void)tif;
+    if (p != NULL && tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
+    {
+        void *oldPtr = (char *)p - LEADING_AREA_TO_STORE_ALLOC_SIZE;
+        tmsize_t oldSize;
+        memcpy(&oldSize, oldPtr, sizeof(oldSize));
+        assert(oldSize <= tif->tif_cur_cumulated_mem_alloc);
+        tif->tif_cur_cumulated_mem_alloc -= oldSize;
+        p = oldPtr;
+    }
     _TIFFfree(p);
 }
 
@@ -231,6 +343,17 @@
                         (uint64_t)opts->max_single_mem_alloc);
         goto bad2;
     }
+    if (opts && opts->max_cumulated_mem_alloc > 0 &&
+        size_to_alloc > opts->max_cumulated_mem_alloc)
+    {
+        _TIFFErrorEarly(opts, clientdata, module,
+                        "%s: Memory allocation of %" PRIu64
+                        " bytes is beyond the %" PRIu64
+                        " cumulated byte limit defined in open options",
+                        name, (uint64_t)size_to_alloc,
+                        (uint64_t)opts->max_cumulated_mem_alloc);
+        goto bad2;
+    }
     tif = (TIFF *)_TIFFmallocExt(NULL, size_to_alloc);
     if (tif == NULL)
     {
@@ -243,6 +366,7 @@
     strcpy(tif->tif_name, name);
     tif->tif_mode = m & ~(O_CREAT | O_TRUNC);
     tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; /* non-existent directory */
+    tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
     tif->tif_curoff = 0;
     tif->tif_curstrip = (uint32_t)-1; /* invalid strip */
     tif->tif_row = (uint32_t)-1;      /* read/write pre-increment */
@@ -261,6 +385,7 @@
         tif->tif_warnhandler = opts->warnhandler;
         tif->tif_warnhandler_user_data = opts->warnhandler_user_data;
         tif->tif_max_single_mem_alloc = opts->max_single_mem_alloc;
+        tif->tif_max_cumulated_mem_alloc = opts->max_cumulated_mem_alloc;
     }
 
     if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc)
@@ -423,9 +548,9 @@
             TIFFErrorExtR(tif, name, "Cannot read TIFF header");
             goto bad;
         }
-/*
- * Setup header and write.
- */
+        /*
+         * Setup header and write.
+         */
 #ifdef WORDS_BIGENDIAN
         tif->tif_header.common.tiff_magic =
             (tif->tif_flags & TIFF_SWAB) ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN;
@@ -433,13 +558,17 @@
         tif->tif_header.common.tiff_magic =
             (tif->tif_flags & TIFF_SWAB) ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN;
 #endif
+        TIFFHeaderUnion tif_header_swapped;
         if (!(tif->tif_flags & TIFF_BIGTIFF))
         {
             tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC;
             tif->tif_header.classic.tiff_diroff = 0;
-            if (tif->tif_flags & TIFF_SWAB)
-                TIFFSwabShort(&tif->tif_header.common.tiff_version);
             tif->tif_header_size = sizeof(TIFFHeaderClassic);
+            /* Swapped copy for writing */
+            _TIFFmemcpy(&tif_header_swapped, &tif->tif_header,
+                        sizeof(TIFFHeaderUnion));
+            if (tif->tif_flags & TIFF_SWAB)
+                TIFFSwabShort(&tif_header_swapped.common.tiff_version);
         }
         else
         {
@@ -447,12 +576,15 @@
             tif->tif_header.big.tiff_offsetsize = 8;
             tif->tif_header.big.tiff_unused = 0;
             tif->tif_header.big.tiff_diroff = 0;
+            tif->tif_header_size = sizeof(TIFFHeaderBig);
+            /* Swapped copy for writing */
+            _TIFFmemcpy(&tif_header_swapped, &tif->tif_header,
+                        sizeof(TIFFHeaderUnion));
             if (tif->tif_flags & TIFF_SWAB)
             {
-                TIFFSwabShort(&tif->tif_header.common.tiff_version);
-                TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize);
+                TIFFSwabShort(&tif_header_swapped.common.tiff_version);
+                TIFFSwabShort(&tif_header_swapped.big.tiff_offsetsize);
             }
-            tif->tif_header_size = sizeof(TIFFHeaderBig);
         }
         /*
          * The doc for "fopen" for some STD_C_LIBs says that if you
@@ -462,27 +594,13 @@
          * on Solaris.
          */
         TIFFSeekFile(tif, 0, SEEK_SET);
-        if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size)))
+        if (!WriteOK(tif, &tif_header_swapped,
+                     (tmsize_t)(tif->tif_header_size)))
         {
             TIFFErrorExtR(tif, name, "Error writing TIFF header");
             goto bad;
         }
         /*
-         * Setup the byte order handling.
-         */
-        if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN)
-        {
-#ifndef WORDS_BIGENDIAN
-            tif->tif_flags |= TIFF_SWAB;
-#endif
-        }
-        else
-        {
-#ifdef WORDS_BIGENDIAN
-            tif->tif_flags |= TIFF_SWAB;
-#endif
-        }
-        /*
          * Setup default directory.
          */
         if (!TIFFDefaultDirectory(tif))
@@ -490,10 +608,14 @@
         tif->tif_diroff = 0;
         tif->tif_lastdiroff = 0;
         tif->tif_setdirectory_force_absolute = FALSE;
+        /* tif_curdircount = 0 means 'empty file opened for writing, but no IFD
+         * written yet' */
+        tif->tif_curdircount = 0;
         return (tif);
     }
+
     /*
-     * Setup the byte order handling.
+     * Setup the byte order handling according to the opened file for reading.
      */
     if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN &&
         tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN
@@ -619,9 +741,17 @@
              * example, it may be broken) and want to proceed to other
              * directories. I this case we use the TIFF_HEADERONLY flag to open
              * file and return immediately after reading TIFF header.
+             * However, the pointer to TIFFSetField() and TIFFGetField()
+             * (i.e. tif->tif_tagmethods.vsetfield and
+             * tif->tif_tagmethods.vgetfield) need to be initialized, which is
+             * done in TIFFDefaultDirectory().
              */
             if (tif->tif_flags & TIFF_HEADERONLY)
+            {
+                if (!TIFFDefaultDirectory(tif))
+                    goto bad;
                 return (tif);
+            }
 
             /*
              * Setup initial directory.
@@ -764,10 +894,7 @@
 /*
  * Return nonzero if given file is BigTIFF style.
  */
-int TIFFIsBigTIFF(TIFF *tif)
-{
-    return (tif->tif_header.common.tiff_version == TIFF_VERSION_BIG);
-}
+int TIFFIsBigTIFF(TIFF *tif) { return ((tif->tif_flags & TIFF_BIGTIFF) != 0); }
 
 /*
  * Return pointer to file read method.
diff --git a/third_party/libtiff/tif_packbits.c b/third_party/libtiff/tif_packbits.c
index 62849f8..1ae50cb 100644
--- a/third_party/libtiff/tif_packbits.c
+++ b/third_party/libtiff/tif_packbits.c
@@ -300,6 +300,7 @@
     tif->tif_rawcc = cc;
     if (occ > 0)
     {
+        memset(op, 0, (size_t)occ);
         TIFFErrorExtR(tif, module, "Not enough data for scanline %" PRIu32,
                       tif->tif_row);
         return (0);
diff --git a/third_party/libtiff/tif_pixarlog.c b/third_party/libtiff/tif_pixarlog.c
index 2e22b33..b4c4c9c 100644
--- a/third_party/libtiff/tif_pixarlog.c
+++ b/third_party/libtiff/tif_pixarlog.c
@@ -670,8 +670,8 @@
     return 1;
 }
 
-#define DecoderState(tif) ((PixarLogState *)(tif)->tif_data)
-#define EncoderState(tif) ((PixarLogState *)(tif)->tif_data)
+#define PixarLogDecoderState(tif) ((PixarLogState *)(tif)->tif_data)
+#define PixarLogEncoderState(tif) ((PixarLogState *)(tif)->tif_data)
 
 static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
 static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
@@ -740,7 +740,7 @@
 {
     static const char module[] = "PixarLogSetupDecode";
     TIFFDirectory *td = &tif->tif_dir;
-    PixarLogState *sp = DecoderState(tif);
+    PixarLogState *sp = PixarLogDecoderState(tif);
     tmsize_t tbuf_size;
     uint32_t strip_height;
 
@@ -813,7 +813,7 @@
 static int PixarLogPreDecode(TIFF *tif, uint16_t s)
 {
     static const char module[] = "PixarLogPreDecode";
-    PixarLogState *sp = DecoderState(tif);
+    PixarLogState *sp = PixarLogDecoderState(tif);
 
     (void)s;
     assert(sp != NULL);
@@ -835,7 +835,7 @@
 {
     static const char module[] = "PixarLogDecode";
     TIFFDirectory *td = &tif->tif_dir;
-    PixarLogState *sp = DecoderState(tif);
+    PixarLogState *sp = PixarLogDecoderState(tif);
     tmsize_t i;
     tmsize_t nsamples;
     int llen;
@@ -859,6 +859,7 @@
             TIFFErrorExtR(tif, module,
                           "%" PRIu16 " bit input not supported in PixarLog",
                           td->td_bitspersample);
+            memset(op, 0, (size_t)occ);
             return 0;
     }
 
@@ -879,12 +880,14 @@
     if (sp->stream.avail_out != nsamples * sizeof(uint16_t))
     {
         TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
+        memset(op, 0, (size_t)occ);
         return (0);
     }
     /* Check that we will not fill more than what was allocated */
     if (sp->tbuf_size < 0 || sp->stream.avail_out > (uInt) sp->tbuf_size)
     {
         TIFFErrorExtR(tif, module, "sp->stream.avail_out > sp->tbuf_size");
+        memset(op, 0, (size_t)occ);
         return (0);
     }
     do
@@ -899,12 +902,14 @@
             TIFFErrorExtR(
                 tif, module, "Decoding error at scanline %" PRIu32 ", %s",
                 tif->tif_row, sp->stream.msg ? sp->stream.msg : "(null)");
+            memset(op, 0, (size_t)occ);
             return (0);
         }
         if (state != Z_OK)
         {
             TIFFErrorExtR(tif, module, "ZLib error: %s",
                           sp->stream.msg ? sp->stream.msg : "(null)");
+            memset(op, 0, (size_t)occ);
             return (0);
         }
     } while (sp->stream.avail_out > 0);
@@ -916,6 +921,7 @@
                       "Not enough data at scanline %" PRIu32
                       " (short %u bytes)",
                       tif->tif_row, sp->stream.avail_out);
+        memset(op, 0, (size_t)occ);
         return (0);
     }
 
@@ -977,6 +983,7 @@
             default:
                 TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16,
                               td->td_bitspersample);
+                memset(op, 0, (size_t)occ);
                 return (0);
         }
     }
@@ -988,7 +995,7 @@
 {
     static const char module[] = "PixarLogSetupEncode";
     TIFFDirectory *td = &tif->tif_dir;
-    PixarLogState *sp = EncoderState(tif);
+    PixarLogState *sp = PixarLogEncoderState(tif);
     tmsize_t tbuf_size;
 
     assert(sp != NULL);
@@ -1038,7 +1045,7 @@
 static int PixarLogPreEncode(TIFF *tif, uint16_t s)
 {
     static const char module[] = "PixarLogPreEncode";
-    PixarLogState *sp = EncoderState(tif);
+    PixarLogState *sp = PixarLogEncoderState(tif);
 
     (void)s;
     assert(sp != NULL);
@@ -1294,7 +1301,7 @@
 {
     static const char module[] = "PixarLogEncode";
     TIFFDirectory *td = &tif->tif_dir;
-    PixarLogState *sp = EncoderState(tif);
+    PixarLogState *sp = PixarLogEncoderState(tif);
     tmsize_t i;
     tmsize_t n;
     int llen;
@@ -1401,7 +1408,7 @@
 static int PixarLogPostEncode(TIFF *tif)
 {
     static const char module[] = "PixarLogPostEncode";
-    PixarLogState *sp = EncoderState(tif);
+    PixarLogState *sp = PixarLogEncoderState(tif);
     int state;
 
     sp->stream.avail_in = 0;
diff --git a/third_party/libtiff/tif_read.c b/third_party/libtiff/tif_read.c
index 4fec839..7efab59 100644
--- a/third_party/libtiff/tif_read.c
+++ b/third_party/libtiff/tif_read.c
@@ -105,8 +105,8 @@
                 TIFFErrorExtR(tif, module, "Invalid buffer size");
                 return 0;
             }
-            new_rawdata =
-                (uint8_t *)_TIFFrealloc(tif->tif_rawdata, tif->tif_rawdatasize);
+            new_rawdata = (uint8_t *)_TIFFreallocExt(tif, tif->tif_rawdata,
+                                                     tif->tif_rawdatasize);
             if (new_rawdata == 0)
             {
                 TIFFErrorExtR(tif, module,
@@ -464,6 +464,10 @@
         if (e)
             (*tif->tif_postdecode)(tif, (uint8_t *)buf, tif->tif_scanlinesize);
     }
+    else
+    {
+        memset(buf, 0, (size_t)tif->tif_scanlinesize);
+    }
     return (e > 0 ? 1 : -1);
 }
 
@@ -495,6 +499,11 @@
     rowsperstrip = td->td_rowsperstrip;
     if (rowsperstrip > td->td_imagelength)
         rowsperstrip = td->td_imagelength;
+    if (rowsperstrip == 0)
+    {
+        TIFFErrorExtR(tif, module, "rowsperstrip is zero");
+        return ((tmsize_t)(-1));
+    }
     stripsperplane =
         TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
     stripinplane = (strip % stripsperplane);
@@ -544,7 +553,10 @@
     if ((size != (tmsize_t)(-1)) && (size < stripsize))
         stripsize = size;
     if (!TIFFFillStrip(tif, strip))
+    {
+        memset(buf, 0, (size_t)stripsize);
         return ((tmsize_t)(-1));
+    }
     if ((*tif->tif_decodestrip)(tif, buf, stripsize, plane) <= 0)
         return ((tmsize_t)(-1));
     (*tif->tif_postdecode)(tif, buf, stripsize);
@@ -962,9 +974,13 @@
         size = tilesize;
     else if (size > tilesize)
         size = tilesize;
-    if (TIFFFillTile(tif, tile) &&
-        (*tif->tif_decodetile)(tif, (uint8_t *)buf, size,
-                               (uint16_t)(tile / td->td_stripsperimage)))
+    if (!TIFFFillTile(tif, tile))
+    {
+        memset(buf, 0, (size_t)size);
+        return ((tmsize_t)(-1));
+    }
+    else if ((*tif->tif_decodetile)(tif, (uint8_t *)buf, size,
+                                    (uint16_t)(tile / td->td_stripsperimage)))
     {
         (*tif->tif_postdecode)(tif, (uint8_t *)buf, size);
         return (size);
@@ -1449,6 +1465,11 @@
         tif->tif_flags |= TIFF_CODERSETUP;
     }
     tif->tif_curtile = tile;
+    if (td->td_tilewidth == 0)
+    {
+        TIFFErrorExtR(tif, module, "Zero tilewidth");
+        return 0;
+    }
     howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
     if (howmany32 == 0)
     {
@@ -1545,9 +1566,14 @@
 
     if (TIFFIsTiled(tif))
     {
-        if (!TIFFStartTile(tif, strile) ||
-            !(*tif->tif_decodetile)(tif, (uint8_t *)outbuf, outsize,
-                                    (uint16_t)(strile / td->td_stripsperimage)))
+        if (!TIFFStartTile(tif, strile))
+        {
+            ret = 0;
+            memset(outbuf, 0, (size_t)outsize);
+        }
+        else if (!(*tif->tif_decodetile)(
+                     tif, (uint8_t *)outbuf, outsize,
+                     (uint16_t)(strile / td->td_stripsperimage)))
         {
             ret = 0;
         }
@@ -1558,14 +1584,27 @@
         uint32_t stripsperplane;
         if (rowsperstrip > td->td_imagelength)
             rowsperstrip = td->td_imagelength;
-        stripsperplane =
-            TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
-        if (!TIFFStartStrip(tif, strile) ||
-            !(*tif->tif_decodestrip)(tif, (uint8_t *)outbuf, outsize,
-                                     (uint16_t)(strile / stripsperplane)))
+        if (rowsperstrip == 0)
         {
+            TIFFErrorExtR(tif, module, "rowsperstrip is zero");
             ret = 0;
         }
+        else
+        {
+            stripsperplane =
+                TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
+            if (!TIFFStartStrip(tif, strile))
+            {
+                ret = 0;
+                memset(outbuf, 0, (size_t)outsize);
+            }
+            else if (!(*tif->tif_decodestrip)(
+                         tif, (uint8_t *)outbuf, outsize,
+                         (uint16_t)(strile / stripsperplane)))
+            {
+                ret = 0;
+            }
+        }
     }
     if (ret)
     {
diff --git a/third_party/libtiff/tif_strip.c b/third_party/libtiff/tif_strip.c
index 820a254..4dbcf37 100644
--- a/third_party/libtiff/tif_strip.c
+++ b/third_party/libtiff/tif_strip.c
@@ -38,6 +38,11 @@
     TIFFDirectory *td = &tif->tif_dir;
     uint32_t strip;
 
+    if (td->td_rowsperstrip == 0)
+    {
+        TIFFErrorExtR(tif, module, "Cannot compute strip: RowsPerStrip is zero");
+        return 0;
+    }
     strip = row / td->td_rowsperstrip;
     if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
     {
@@ -61,6 +66,11 @@
     TIFFDirectory *td = &tif->tif_dir;
     uint32_t nstrips;
 
+    if (td->td_rowsperstrip == 0)
+    {
+        TIFFWarningExtR(tif, "TIFFNumberOfStrips", "RowsPerStrip is zero");
+        return 0;
+    }
     nstrips = (td->td_rowsperstrip == (uint32_t)-1
                    ? 1
                    : TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip));
@@ -107,7 +117,8 @@
         if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 &&
              ycbcrsubsampling[0] != 4) ||
             (ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 &&
-             ycbcrsubsampling[1] != 4))
+             ycbcrsubsampling[1] != 4) ||
+            (ycbcrsubsampling[0] == 0 || ycbcrsubsampling[1] == 0))
         {
             TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling (%dx%d)",
                           ycbcrsubsampling[0], ycbcrsubsampling[1]);
@@ -267,7 +278,8 @@
             if (((ycbcrsubsampling[0] != 1) && (ycbcrsubsampling[0] != 2) &&
                  (ycbcrsubsampling[0] != 4)) ||
                 ((ycbcrsubsampling[1] != 1) && (ycbcrsubsampling[1] != 2) &&
-                 (ycbcrsubsampling[1] != 4)))
+                 (ycbcrsubsampling[1] != 4)) ||
+                ((ycbcrsubsampling[0] == 0) || (ycbcrsubsampling[1] == 0)))
             {
                 TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling");
                 return 0;
@@ -287,7 +299,25 @@
         else
         {
             uint64_t scanline_samples;
-            scanline_samples = _TIFFMultiply64(tif, td->td_imagewidth,
+            uint32_t scanline_width = td->td_imagewidth;
+
+#if 0
+            // Tries to fix https://gitlab.com/libtiff/libtiff/-/merge_requests/564
+            // but causes regression when decoding legit files with tiffcp -c none
+            // Cf https://gitlab.com/libtiff/libtiff/-/merge_requests/644
+            if (td->td_photometric == PHOTOMETRIC_YCBCR)
+            {
+                uint16_t subsampling_hor;
+                uint16_t ignored;
+                TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING,
+                                      &subsampling_hor, &ignored);
+                if (subsampling_hor > 1) // roundup width for YCbCr
+                    scanline_width =
+                        TIFFroundup_32(scanline_width, subsampling_hor);
+            }
+#endif
+
+            scanline_samples = _TIFFMultiply64(tif, scanline_width,
                                                td->td_samplesperpixel, module);
             scanline_size =
                 TIFFhowmany_64(_TIFFMultiply64(tif, scanline_samples,
diff --git a/third_party/libtiff/tif_thunder.c b/third_party/libtiff/tif_thunder.c
index 1f97362..bac0607 100644
--- a/third_party/libtiff/tif_thunder.c
+++ b/third_party/libtiff/tif_thunder.c
@@ -82,13 +82,14 @@
     return (1);
 }
 
-static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels)
+static int ThunderDecode(TIFF *tif, uint8_t *op0, tmsize_t maxpixels)
 {
     static const char module[] = "ThunderDecode";
     register unsigned char *bp;
     register tmsize_t cc;
     unsigned int lastpixel;
     tmsize_t npixels;
+    uint8_t *op = op0;
 
     bp = (unsigned char *)tif->tif_rawcp;
     cc = tif->tif_rawcc;
@@ -107,6 +108,8 @@
                  * Replicate the last pixel n times,
                  * where n is the lower-order 6 bits.
                  */
+                if (n == 0)
+                    break;
                 if (npixels & 1)
                 {
                     op[0] |= lastpixel;
@@ -117,11 +120,10 @@
                 else
                     lastpixel |= lastpixel << 4;
                 npixels += n;
-                if (npixels < maxpixels)
-                {
-                    for (; n > 0; n -= 2)
-                        *op++ = (uint8_t)lastpixel;
-                }
+                if (npixels > maxpixels)
+                    break;
+                for (; n > 0; n -= 2)
+                    *op++ = (uint8_t)lastpixel;
                 if (n == -1)
                     *--op &= 0xf0;
                 lastpixel &= 0xf;
@@ -154,6 +156,8 @@
     tif->tif_rawcc = cc;
     if (npixels != maxpixels)
     {
+        uint8_t *op_end = op0 + (maxpixels + 1) / 2;
+        memset(op, 0, (size_t)(op_end - op));
         TIFFErrorExtR(tif, module,
                       "%s data at scanline %lu (%" PRIu64 " != %" PRIu64 ")",
                       npixels < maxpixels ? "Not enough" : "Too much",
diff --git a/third_party/libtiff/tiffconf.h b/third_party/libtiff/tiffconf.h
index 289f175..beba8b8 100644
--- a/third_party/libtiff/tiffconf.h
+++ b/third_party/libtiff/tiffconf.h
@@ -175,11 +175,7 @@
 
 /* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
    (Intel) */
-#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_
-# define HOST_BIGENDIAN 1
-#else
-# define HOST_BIGENDIAN 0
-#endif
+#define HOST_BIGENDIAN 0
 
 /* Support CCITT Group 3 & 4 algorithms */
 #define CCITT_SUPPORT 1
@@ -213,7 +209,7 @@
 /* #undef ZIP_SUPPORT */
 
 /* Support strip chopping (whether or not to convert single-strip uncompressed
-   images to mutiple strips of ~8Kb to reduce memory usage) */
+   images to multiple strips of ~8Kb to reduce memory usage) */
 #define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
 
 /* Enable SubIFD tag (330) support */
diff --git a/third_party/libtiff/tiffio.h b/third_party/libtiff/tiffio.h
index 2046054..225f3c1 100644
--- a/third_party/libtiff/tiffio.h
+++ b/third_party/libtiff/tiffio.h
@@ -77,10 +77,6 @@
 typedef tmsize_t tsize_t;   /* i/o size in bytes */
 typedef void *tdata_t;      /* image data ref */
 
-#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32))
-#define __WIN32__
-#endif
-
 /*
  * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c
  * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c).
@@ -88,7 +84,7 @@
  * By default tif_unix.c is assumed.
  */
 
-#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows)
+#if defined(_WIN32)
 #if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) &&                      \
     !defined(USE_WIN32_FILEIO)
 #define AVOID_WIN32_FILEIO
@@ -98,11 +94,11 @@
 #if defined(USE_WIN32_FILEIO)
 #define VC_EXTRALEAN
 #include <windows.h>
-#ifdef __WIN32__
+#ifdef _WIN32
 DECLARE_HANDLE(thandle_t); /* Win32 file handle */
 #else
 typedef HFILE thandle_t; /* client data handle */
-#endif /* __WIN32__ */
+#endif /* _WIN32 */
 #else
 typedef void *thandle_t; /* client data handle */
 #endif /* USE_WIN32_FILEIO */
@@ -311,14 +307,15 @@
     /*
      * Auxiliary functions.
      */
-
+#ifndef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
     extern void *_TIFFmalloc(tmsize_t s);
     extern void *_TIFFcalloc(tmsize_t nmemb, tmsize_t siz);
     extern void *_TIFFrealloc(void *p, tmsize_t s);
+    extern void _TIFFfree(void *p);
+#endif
     extern void _TIFFmemset(void *p, int v, tmsize_t c);
     extern void _TIFFmemcpy(void *d, const void *s, tmsize_t c);
     extern int _TIFFmemcmp(const void *p1, const void *p2, tmsize_t c);
-    extern void _TIFFfree(void *p);
 
     /*
     ** Stuff, related to tag handling and creating custom tags.
@@ -508,6 +505,9 @@
     TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts,
                                         tmsize_t max_single_mem_alloc);
     extern void
+    TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts,
+                                           tmsize_t max_cumulated_mem_alloc);
+    extern void
     TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts,
                                        TIFFErrorHandlerExtR handler,
                                        void *errorhandler_user_data);
@@ -518,11 +518,11 @@
 
     extern TIFF *TIFFOpen(const char *, const char *);
     extern TIFF *TIFFOpenExt(const char *, const char *, TIFFOpenOptions *opts);
-#ifdef __WIN32__
+#ifdef _WIN32
     extern TIFF *TIFFOpenW(const wchar_t *, const char *);
     extern TIFF *TIFFOpenWExt(const wchar_t *, const char *,
                               TIFFOpenOptions *opts);
-#endif /* __WIN32__ */
+#endif /* _WIN32 */
     extern TIFF *TIFFFdOpen(int, const char *, const char *);
     extern TIFF *TIFFFdOpenExt(int, const char *, const char *,
                                TIFFOpenOptions *opts);
diff --git a/third_party/libtiff/tiffiop.h b/third_party/libtiff/tiffiop.h
index a7cc12b..d861fd5 100644
--- a/third_party/libtiff/tiffiop.h
+++ b/third_party/libtiff/tiffiop.h
@@ -102,6 +102,13 @@
 };
 typedef struct TIFFOffsetAndDirNumber TIFFOffsetAndDirNumber;
 
+typedef union
+{
+    TIFFHeaderCommon common;
+    TIFFHeaderClassic classic;
+    TIFFHeaderBig big;
+} TIFFHeaderUnion;
+
 struct tiff
 {
     char *tif_name; /* name of open file */
@@ -153,20 +160,35 @@
     TIFFDirectory tif_dir;               /* internal rep of current directory */
     TIFFDirectory
         tif_customdir; /* custom IFDs are separated from the main ones */
-    union
-    {
-        TIFFHeaderCommon common;
-        TIFFHeaderClassic classic;
-        TIFFHeaderBig big;
-    } tif_header;
-    uint16_t tif_header_size;  /* file's header block and its length */
-    uint32_t tif_row;          /* current scanline */
-    tdir_t tif_curdir;         /* current directory (index) */
+    TIFFHeaderUnion tif_header; /* file's header block Classic/BigTIFF union */
+    uint16_t tif_header_size;   /* file's header block and its length */
+    uint32_t tif_row;           /* current scanline */
+
+    /* There are IFDs in the file and an "active" IFD in memory,
+     * from which fields are "set" and "get".
+     * tif_curdir is set to:
+     *   a) TIFF_NON_EXISTENT_DIR_NUMBER if there is no IFD in the file
+     *      or the state is unknown,
+     *      or the last read (i.e. TIFFFetchDirectory()) failed,
+     *      or a custom directory was written.
+     *   b) IFD index of last IFD written in the file. In this case the
+     *      active IFD is a new (empty) one and tif_diroff is zero.
+     *      If writing fails, tif_curdir is not changed.
+     *   c) IFD index of IFD read from file into memory (=active IFD),
+     *      even if IFD is corrupt and TIFFReadDirectory() returns 0.
+     *      Then tif_diroff contains the offset of the IFD in the file.
+     *   d) IFD index 0, whenever a custom directory or an unchained SubIFD
+     *      was read. */
+    tdir_t tif_curdir; /* current directory (index) */
+    /* tif_curdircount: number of directories (main-IFDs) in file:
+     * - TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs'.
+     * - 0 means 'empty file opened for writing, but no IFD written yet' */
+    tdir_t tif_curdircount;
     uint32_t tif_curstrip;     /* current strip for read/write */
     uint64_t tif_curoff;       /* current offset for read/write */
     uint64_t tif_lastvalidoff; /* last valid offset allowed for rewrite in
                                   place. Used only by TIFFAppendToStrip() */
-    uint64_t tif_dataoff;      /* current offset for writing dir */
+    uint64_t tif_dataoff;      /* current offset for writing dir (IFD) */
     /* SubIFD support */
     uint16_t tif_nsubifd;   /* remaining subifds to write */
     uint64_t tif_subifdoff; /* offset for patching SubIFD link */
@@ -233,7 +255,9 @@
     void *tif_errorhandler_user_data;
     TIFFErrorHandlerExtR tif_warnhandler;
     void *tif_warnhandler_user_data;
-    tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */
+    tmsize_t tif_max_single_mem_alloc;    /* in bytes. 0 for unlimited */
+    tmsize_t tif_max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */
+    tmsize_t tif_cur_cumulated_mem_alloc; /* in bytes */
 };
 
 struct TIFFOpenOptions
@@ -243,6 +267,7 @@
     TIFFErrorHandlerExtR warnhandler;  /* may be NULL */
     void *warnhandler_user_data;       /* may be NULL */
     tmsize_t max_single_mem_alloc;     /* in bytes. 0 for unlimited */
+    tmsize_t max_cumulated_mem_alloc;  /* in bytes. 0 for unlimited */
 };
 
 #define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */
@@ -331,7 +356,7 @@
 #define ftell(stream, offset, whence) ftello(stream, offset, whence)
 #endif
 #endif
-#if defined(__WIN32__) && !(defined(_MSC_VER) && _MSC_VER < 1400) &&           \
+#if defined(_WIN32) &&                                                         \
     !(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x800)
 typedef unsigned int TIFFIOSize_t;
 #define _TIFF_lseek_f(fildes, offset, whence)                                  \
@@ -437,9 +462,6 @@
     extern void *_TIFFCheckRealloc(TIFF *, void *, tmsize_t, tmsize_t,
                                    const char *);
 
-    extern double _TIFFUInt64ToDouble(uint64_t);
-    extern float _TIFFUInt64ToFloat(uint64_t);
-
     extern float _TIFFClampDoubleToFloat(double);
     extern uint32_t _TIFFClampDoubleToUInt32(double);
 
diff --git a/third_party/libtiff/tiffvers.h b/third_party/libtiff/tiffvers.h
index 5741347..3ded6ac 100644
--- a/third_party/libtiff/tiffvers.h
+++ b/third_party/libtiff/tiffvers.h
@@ -3,7 +3,7 @@
 /* clang-format disabled because FindTIFF.cmake is very sensitive to the
  * formatting of below line being a single line.
  */
-#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.6.0\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc."
+#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.7.0\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc."
 /*
  * This define can be used in code that requires
  * compilation-related definitions specific to a
@@ -11,11 +11,11 @@
  * version checking should be done based on the
  * string returned by TIFFGetVersion.
  */
-#define TIFFLIB_VERSION 20230908
+#define TIFFLIB_VERSION 20240911
 
 /* The following defines have been added in 4.5.0 */
 #define TIFFLIB_MAJOR_VERSION 4
-#define TIFFLIB_MINOR_VERSION 6
+#define TIFFLIB_MINOR_VERSION 7
 #define TIFFLIB_MICRO_VERSION 0
 
 /* Macro added in 4.5.0. Returns TRUE if the current libtiff version is