From 1f100c0c4272aa66ffc54734f59f80722ed1829c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 31 Mar 2019 12:55:30 +0100 Subject: [PATCH] better buffer sizing in tiff reader We were not setting JPEGCOLORMODE_RGB early enough, so buffers could be undersized in some circumstances. Thanks omira-sch. --- ChangeLog | 3 ++ configure.ac | 6 ++-- libvips/foreign/tiff2vips.c | 65 +++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7877a037..1cadba4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +31/3/19 started 8.7.5 +- better buffer sizing in tiff reader [omira-sch] + 4/1/19 started 8.7.4 - zero memory on allocate to prevent write of uninitialized memory under some error conditions [Balint Varga-Perke] diff --git a/configure.ac b/configure.ac index f3c6abc6..0132e80a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # also update the version number in the m4 macros below -AC_INIT([vips], [8.7.4], [vipsip@jiscmail.ac.uk]) +AC_INIT([vips], [8.7.5], [vipsip@jiscmail.ac.uk]) # required for gobject-introspection AC_PREREQ(2.62) @@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4]) # user-visible library versioning m4_define([vips_major_version], [8]) m4_define([vips_minor_version], [7]) -m4_define([vips_micro_version], [4]) +m4_define([vips_micro_version], [5]) m4_define([vips_version], [vips_major_version.vips_minor_version.vips_micro_version]) @@ -38,7 +38,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date -u -r ChangeLog` # binary interface changes not backwards compatible?: reset age to 0 LIBRARY_CURRENT=51 -LIBRARY_REVISION=5 +LIBRARY_REVISION=6 LIBRARY_AGE=9 # patched into include/vips/version.h diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index f05fd4e9..e370df5c 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -183,6 +183,8 @@ * - check for non-byte-multiple bits_per_sample [HongxuChen] * 16/8/18 * - shut down the input file as soon as we can [kleisauke] + * 28/3/19 omira-sch + * - better buffer sizing */ /* @@ -264,6 +266,7 @@ typedef struct _RtiffHeader { */ uint32 rows_per_strip; tsize_t strip_size; + tsize_t tile_size; int number_of_strips; gboolean read_scanlinewise; } RtiffHeader; @@ -1291,14 +1294,6 @@ rtiff_pick_reader( Rtiff *rtiff ) if( photometric_interpretation == PHOTOMETRIC_PALETTE ) return( rtiff_parse_palette ); - if( photometric_interpretation == PHOTOMETRIC_YCBCR ) { - /* Sometimes JPEG in TIFF images are tagged as YCBCR. Ask - * libtiff to convert to RGB for us. - */ - TIFFSetField( rtiff->tiff, - TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); - } - return( rtiff_parse_copy ); } @@ -1311,6 +1306,10 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out ) uint32 data_length; void *data; + /* Request YCbCr expansion. + */ + TIFFSetField( rtiff->tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); + out->Xsize = rtiff->header.width; out->Ysize = rtiff->header.height * rtiff->n; @@ -1438,19 +1437,6 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out ) return( 0 ); } -/* The size of the buffer written by TIFFReadTile(). We can't use - * TIFFTileSize() since that ignores the setting of TIFFTAG_JPEGCOLORMODE. If - * this pseudo tag has been set and the tile is encoded with YCbCr, the tile - * is returned with chrominance upsampled. - * - * This seems not to happen for old-style jpeg-compressed tiles. - */ -static size_t -rtiff_tile_size( Rtiff *rtiff ) -{ - return( TIFFTileRowSize( rtiff->tiff ) * rtiff->header.tile_height ); -} - /* Allocate a tile buffer. Have one of these for each thread so we can unpack * to vips in parallel. */ @@ -1458,11 +1444,9 @@ static void * rtiff_seq_start( VipsImage *out, void *a, void *b ) { Rtiff *rtiff = (Rtiff *) a; - tsize_t size; tdata_t *buf; - size = rtiff_tile_size( rtiff ); - if( !(buf = vips_malloc( NULL, size )) ) + if( !(buf = vips_malloc( NULL, rtiff->header.tile_size )) ) return( NULL ); return( (void *) buf ); @@ -1531,7 +1515,7 @@ rtiff_fill_region( VipsRegion *out, /* Sizeof a line of bytes in the TIFF tile. */ - int tls = rtiff_tile_size( rtiff ) / tile_height; + int tls = rtiff->header.tile_size / tile_height; /* Sizeof a pel in the TIFF file. This won't work for formats which * are <1 byte per pel, like onebit :-( Fortunately, it's only used @@ -1726,7 +1710,7 @@ rtiff_read_tilewise( Rtiff *rtiff, VipsImage *out ) vips_tile_size = VIPS_IMAGE_SIZEOF_PEL( t[0] ) * tile_width * tile_height; - if( rtiff_tile_size( rtiff ) != vips_tile_size ) { + if( rtiff->header.tile_size != vips_tile_size ) { vips_error( "tiff2vips", "%s", _( "unsupported tiff image type" ) ); return( -1 ); @@ -2039,7 +2023,6 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out ) if( !(rtiff->contig_buf = vips_malloc( VIPS_OBJECT( out ), size )) ) return( -1 ); - } if( @@ -2061,6 +2044,12 @@ rtiff_read_stripwise( Rtiff *rtiff, VipsImage *out ) static int rtiff_header_read( Rtiff *rtiff, RtiffHeader *header ) { + /* We want to always expand subsampled YCBCR images to full RGB. We + * need to set this pseudo tag early, since it affects the value you + * get from TIFFStripSize() etc. + */ + TIFFSetField( rtiff->tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); + if( !tfget32( rtiff->tiff, TIFFTAG_IMAGEWIDTH, &header->width ) || !tfget32( rtiff->tiff, TIFFTAG_IMAGELENGTH, &header->height ) || !tfget16( rtiff->tiff, @@ -2074,11 +2063,11 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header ) /* Arbitrary sanity-checking limits. */ - if( header->width <= 0 || - header->width > VIPS_MAX_COORD || - header->height <= 0 || + if( header->width <= 0 || + header->width > VIPS_MAX_COORD || + header->height <= 0 || header->height > VIPS_MAX_COORD ) { - vips_error( "tiff2vips", + vips_error( "tiff2vips", "%s", _( "width/height out of range" ) ); return( -1 ); } @@ -2116,6 +2105,19 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header ) TIFFTAG_TILELENGTH, &header->tile_height ) ) return( -1 ); + /* Arbitrary sanity-checking limits. + */ + if( header->tile_width <= 0 || + header->tile_width > 10000 || + header->tile_height <= 0 || + header->tile_height > 10000 ) { + vips_error( "tiff2vips", + "%s", _( "tile size out of range" ) ); + return( -1 ); + } + + header->tile_size = TIFFTileSize( rtiff->tiff ); + /* Stop some compiler warnings. */ header->rows_per_strip = 0; @@ -2162,6 +2164,7 @@ rtiff_header_read( Rtiff *rtiff, RtiffHeader *header ) */ header->tile_width = 0; header->tile_height = 0; + header->tile_size = 0; } return( 0 );