2016.09.19 16:29 "[Tiff] Accuracy of TIFF Field metadata (COLORMAP)", by

2016.09.19 16:29 "[Tiff] Accuracy of TIFF Field metadata (COLORMAP)", by

I recently discovered a problem on Windows where I was getting a strange runtime error ("Run-Time Check Failure #2 -S") which turns out was due to stack corruption. This was due to calling TIFFGetField with the wrong parameters, and that was because the field metadata in tif_dirinfo.c was wrong. Here's the broken bit:

         { TIFFTAG_COLORMAP, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_OTHER,

TIFF_SETGET_UNDEFINED, FIELD_COLORMAP, 1, 0, "ColorMap", NULL },

It's the "-1, -1," values which map to TIFF_VARIABLE. It should be -2 which is TIFF_SPP. At least, that's my understanding (which could be wrong).

I wrote a set of type-safe generic tag processing functions in C++ which make use of the metadata and expect it to be correct. The logic is essentially this for the three-array variant:

           int readcount = TIFFFieldReadCount(field);

           typename T::value_type::value_type *valueptr0, *valueptr1, 

*valueptr2; // type of array of array of values
           uint32_t count;

           if (readcount == TIFF_SPP)
             {
               uint16_t spp;
               ifd->getRawField(TIFFTAG_SAMPLESPERPIXEL, &spp);
               ifd->getRawField(tag, &valueptr0, &valueptr1, &valueptr2);
               count = static_cast<uint32_t>(spp);
             }
           else if (readcount == TIFF_VARIABLE)
             {
               uint16_t n;
               ifd->getRawField(tag, &n, &valueptr0, &valueptr1,
&valueptr2);
               count = static_cast<uint32_t>(n);
             }
           else if (readcount == TIFF_VARIABLE2)
             {
               ifd->getRawField(tag, &count, &valueptr0, &valueptr1,
&valueptr2);
             }
           else
             {
               if (!limit)
                 ifd->getRawField(tag, &valueptr0, &valueptr1,
&valueptr2);
               else
                 ifd->getRawField(tag, &valueptr0);
               count = static_cast<uint32_t>(readcount);
             }

           // copy valueptr[0-2] + count into destination array(s)

Note: it's using wrappers around libtiff, but getRawField is essentially TIFFGetField with added locking for thread safety. (https://github.com/ome/ome-files-cpp/blob/develop/lib/ome/files/tiff/Field.cpp#L522 is the actual code and https://github.com/ome/ome-files-cpp/blob/develop/lib/ome/files/in/OMETIFFReader.cpp#L817 is an example of its use)

Since I'm hitting the TIFF_VARIABLE case, I'm clearly calling TIFFGetField with the wrong arguments and this ends up trashing the stack (since we're storing a 64-bit pointer in a 16-bit type).

Assuming I'm not totally wrong in my understanding, the wider question here is this: is the field metadata generally usable? Or does it need a proper audit of every field to ensure the types are correct in every case? Would it help to use the VARIABLE/VARIABLE2/SPP values in place of negative values?

Regards,

Roger

--
Dr Roger Leigh -- Open Microscopy Environment

Wellcome Trust Centre for Gene Regulation and Expression, School of Life Sciences, University of Dundee, Dow Street, Dundee DD1 5EH Scotland UK Tel: (01382) 386364