
Thread
2009.05.19 12:32 "[Tiff] Heap corruption caused by TIFFRGBAImageGet() + TIFFSetDirectory() + TIFFRewriteDirectory()", by
TIFFStartStrip() uses the raw buffer for *reading* data and sets tif_rawcc to a positive value:
tif->tif_rawcc = td->td_stripbytecount[strip];
TIFFReadDirectory() resets tif_curstrip to -1, but doesn't reset tif_rawcc to 0:
tif->tif_curstrip = (tstrip_t) -1;
In consequence, the next call to _TIFFWriteDirectory() thinks there is pending data to *write*:
if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) {
and TIFFAppendToStrip() will modify td_stripoffset[-1] (as strip = tif->tif_curstrip = (tstrip_t)-1):
td->td_stripoffset[strip]
=
TIFFSeekFile(tif,
(toff_t)0,
SEEK_END);
Probably ditto for tiled images. There seems to be no way to reset tif_rawcc to 0 with the official
API except for reopening the image.
When built with dmalloc, the program below will result in this output:
libtiff version: LIBTIFF, Version 3.8.2
Copyright (c) 1988-1996 Sam Leffler
Copyright (c) 1991-1996 Silicon Graphics, Inc.
tif_rawcc=115
tif_curtile=-1
tif_curstrip=2338
tif_rawcc=115
tif_curtile=-1
tif_curstrip=-1
debug-malloc library: dumping program, fatal error
Error: failed UNDER picket-fence magic-number check (err 26)
Aborted
Here's the program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "tiffio.h"
#ifdef HAVE_TIFFIOP_H
#include "tiffiop.h"
#endif
static void show (TIFF *tif)
{
#ifdef HAVE_TIFFIOP_H
printf ("tif_rawcc=%ld\n", (long)tif->tif_rawcc);
printf ("tif_curtile=%ld\n", (long)tif->tif_curtile);
printf ("tif_curstrip=%ld\n", (long)tif->tif_curstrip);
printf ("\n");
#endif
}
int main (int argc, char *argv[])
{
const char *path;
TIFF *tif;
uint32 width, height;
TIFFRGBAImage img;
size_t size;
uint32 *raster;
char msg[1024];
printf ("libtiff version: %s\n", TIFFGetVersion ());
if (argc != 2)
{
fprintf (stderr, "Usage: %s TIFF_FILE\n", argv[0]);
exit (1);
}
path = argv[1];
tif = TIFFOpen (path, "r+");
if (tif == NULL)
{
perror (path);
exit (2);
}
if (TIFFRGBAImageOK (tif, msg) != 1)
{
fprintf (stderr, "Cannot process image as RGBA (%s)\n", msg);
exit (2);
}
if (TIFFRGBAImageBegin (&img, tif, 1, msg) != 1)
{
fprintf (stderr, "TIFFRGBAImageBegin failed (%s)\n", msg);
exit (2);
}
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height);
size = (size_t)-1;
if (width > size / height / sizeof (uint32))
{
fprintf (stderr, "Image too big\n");
exit (2);
}
size = width * height * sizeof (uint32);
raster = (uint32 *)malloc (size);
if (raster == NULL)
{
fprintf (stderr, "Out of memory\n");
exit (2);
}
if (TIFFRGBAImageGet (&img, raster, width, height) != 1)
{
fprintf (stderr, "TIFFRGBAImageGet failed\n");
exit (2);
}
TIFFRGBAImageEnd (&img);
show (tif);
if (TIFFSetDirectory (tif, 0) != 1)
{
fprintf (stderr, "TIFFSetDirectory failed\n");
exit (2);
}
show (tif);
/*... set some fields here... */
if (TIFFRewriteDirectory (tif) != 1)
{
fprintf (stderr, "TIFFRewriteDirectory failed\n");
exit (2);
}
TIFFClose (tif);
return 0;
}