2020.08.03 21:27 "[Tiff] Unable to read a large TIFF File (single image, one IFD, Strip image of size 2.6 GB) on Unix using TIFFClientOpen API", by Upanita Goswami

2020.08.07 04:13 "Re: [Tiff] Unable to read a large TIFF File (single image, one IFD, Strip image of size 2.6 GB) on Unix using TIFFClientOpen API", by Adam Richter

Hi, Upanita and libtiff developers.

'TIFFFillStrip: Read error at scanline 4294967295; got 2263871488 bytes, expected 2637881541.'

2147479552 is 0x7ffff000, So, this is probably an overflow of a signed 32-bit counter.

The first point where I see that this could happen is when _TIFFFetchStrileValue calls _TIFFPartialReadStripArray, implicitly casting uint32 parameter "strile" to an int. Because this is the only call site for that function and it is private to that source file, we can fix the parameter declaration to avoid the implicit cast and fix the signed-unsigned comparison that probably motivated that incompatibility.

I am not a libtiff developer, but I have made the following patch, which I have only just observed to compile without complaint on x86-64. I have not tried it. I believe it fixes a bug, but I am less confident that it will completely fix the reported problem. Upanita, if you are able to try this patch and let the list know what happens, that would be great. Also, as Bob has mentioned, if you can post a method for reproducing your problem, that would also be very helpful.

I hereby release any copyright interest in the attached patch to the public domain. Libtiff developers, if you want some further statement along those lines, please just let me know. You are welcome to merge the change. If Upanita indicates that this patch fixes the symptom, I will also look through the documentation for instructions on the contribution process as time allows, but please feel free to grab this patch and merge it without waiting for me if you see fit.

Adam

diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
index f7984aae..0da8371e 100644
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -6076,7 +6076,7 @@ static uint64 _TIFFUnsanitizedAddUInt64AndInt(uint64 a, int b)
  */
 static
 int _TIFFPartialReadStripArray( TIFF* tif, TIFFDirEntry* dirent,
-                                int strile, uint64* panVals )
+                                uint32 strile, uint64* panVals )
 {
     static const char module[] = "_TIFFPartialReadStripArray";
 #define IO_CACHE_PAGE_SIZE 4096
@@ -6180,10 +6180,13 @@ int _TIFFPartialReadStripArray( TIFF* tif, TIFFDirEntry* dirent,
                  "Cannot read offset/size for strile around ~%d", strile);
         return 0;
     }
-    iStartBefore = -(int)((nOffset - nOffsetStartPage) / sizeofval);
-    if( strile + iStartBefore < 0 )
-        iStartBefore = -strile;
-    for( i = iStartBefore;
+    iStartBefore = (nOffset - nOffsetStartPage) / sizeofval;
+    /* iStartBefore is in the range 0 .. I_CACHE_PAGE_SIZE - 1,
+       so it can can safely be cast to uint32 for this comparison: */
+    if( ((uint32) iStartBefore) > strile )
+        iStartBefore = strile;
+
+    for( i = -iStartBefore;
          (uint32)(strile + i) < arraySize &&
          _TIFFUnsanitizedAddUInt64AndInt(nOffset, (i + 1) * sizeofvalint) <= nOffsetEndPage;
          ++i )