mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
IDAT read buffering correction
The sequential read code failed to read to the end of the IDAT stream in about 1/820 cases, resulting in a spurious warning. The png_set_compression_buffer_size API also would not work (or do bad things) if the size of a zlib uInt was less than 32 bits. This includes a quiet API change to alter png_set_compression_buffer_size to use a png_alloc_size_t, not png_size_t and implement the correct checks. Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
parent
e393f19527
commit
1afbb57994
16
png.h
16
png.h
@ -1113,11 +1113,21 @@ PNG_EXPORTA(5, png_structp, png_create_write_struct,
|
||||
png_error_ptr warn_fn),
|
||||
PNG_ALLOCATED);
|
||||
|
||||
PNG_EXPORT(6, size_t, png_get_compression_buffer_size,
|
||||
/* These APIs control the sie of the buffer used when reading IDAT chunks in the
|
||||
* sequential read code and the size of the IDAT chunks produced when writing.
|
||||
* They have no effect on the progressive read code. In both read and write
|
||||
* cases it will be necessary to allocate at least this amount of buffer space.
|
||||
* The default value is PNG_IDAT_READ_SIZE on read and PNG_ZBUF_SIZE on write.
|
||||
*
|
||||
* The valid range is 1..0x7FFFFFFF on write and 1..max(uInt) on read, where
|
||||
* uInt is the type declared by zlib.h. On write setting the largest value will
|
||||
* typically cause the PNG image data to be written in one chunk; this gives the
|
||||
* smallest PNG and has little or no effect on applications that read the PNG.
|
||||
*/
|
||||
PNG_EXPORT(6, png_alloc_size_t, png_get_compression_buffer_size,
|
||||
(png_const_structrp png_ptr));
|
||||
|
||||
PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr,
|
||||
size_t size));
|
||||
png_alloc_size_t size));
|
||||
|
||||
/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp
|
||||
* match up.
|
||||
|
||||
2
pngget.c
2
pngget.c
@ -1144,7 +1144,7 @@ png_get_user_chunk_ptr(png_const_structrp png_ptr)
|
||||
}
|
||||
#endif
|
||||
|
||||
png_size_t PNGAPI
|
||||
png_alloc_size_t PNGAPI
|
||||
png_get_compression_buffer_size(png_const_structrp png_ptr)
|
||||
{
|
||||
if (png_ptr == NULL)
|
||||
|
||||
27
pngread.c
27
pngread.c
@ -308,17 +308,18 @@ png_start_read_image(png_structrp png_ptr)
|
||||
static void
|
||||
png_read_IDAT(png_structrp png_ptr)
|
||||
{
|
||||
/* Read more input data, up to png_struct::IDAT_size, stop at the
|
||||
* end of the IDAT stream:
|
||||
/* Read more input data, up to png_struct::IDAT_size, stop at the end of the
|
||||
* IDAT stream. pngset.c checks png_struct::IDAT_size to ensure that it will
|
||||
* fit in a uInt.
|
||||
*/
|
||||
const uInt buffer_size = (uInt)/*SAFE*/png_ptr->IDAT_size;
|
||||
uInt IDAT_size = 0;
|
||||
png_bytep buffer =
|
||||
png_read_buffer(png_ptr, png_ptr->IDAT_size, 0/*error*/);
|
||||
png_read_buffer(png_ptr, buffer_size, 0/*error*/);
|
||||
|
||||
png_ptr->zstream.next_in = buffer;
|
||||
|
||||
while (png_ptr->chunk_name == png_IDAT &&
|
||||
IDAT_size < png_ptr->IDAT_size)
|
||||
while (png_ptr->chunk_name == png_IDAT && IDAT_size < buffer_size)
|
||||
{
|
||||
png_uint_32 l = png_ptr->chunk_length;
|
||||
|
||||
@ -338,11 +339,11 @@ png_read_IDAT(png_structrp png_ptr)
|
||||
|
||||
/* Read from the IDAT chunk into the buffer, up to png_struct::IDAT_size:
|
||||
*/
|
||||
if (l > png_ptr->IDAT_size - IDAT_size) /* SAFE: while check */
|
||||
l = png_ptr->IDAT_size - IDAT_size;
|
||||
if (l > buffer_size - IDAT_size) /* SAFE: while check */
|
||||
l = buffer_size - IDAT_size;
|
||||
|
||||
png_crc_read(png_ptr, buffer+IDAT_size, l);
|
||||
IDAT_size += /*SAFE*/l;
|
||||
IDAT_size += (uInt)/*SAFE*/l;
|
||||
png_ptr->chunk_length -= l;
|
||||
}
|
||||
|
||||
@ -612,7 +613,15 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
|
||||
{
|
||||
if (png_ptr->zowner == png_IDAT)
|
||||
{
|
||||
/* Normal case: read to the end of the IDAT chunks. */
|
||||
/* Normal case: read to the end of the IDAT chunks. In about
|
||||
* 5/PNG_IDAT_READ_SIZE cases (typically that's 1:820) zlib will have
|
||||
* returned all the image data but not read up to the end of the
|
||||
* Adler32 because the end of the stream had not been read. Make sure
|
||||
* it gets read here:
|
||||
*/
|
||||
if (png_ptr->zstream.avail_in == 0)
|
||||
png_read_IDAT(png_ptr);
|
||||
|
||||
while (!png_read_finish_IDAT(png_ptr)) {
|
||||
/* This will adjust zstream.next/avail_in appropriately and if
|
||||
* necessary read the next chunk. After this avail_in may still
|
||||
|
||||
7
pngset.c
7
pngset.c
@ -1596,16 +1596,17 @@ png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
#endif
|
||||
|
||||
void PNGAPI
|
||||
png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
|
||||
png_set_compression_buffer_size(png_structrp png_ptr, png_alloc_size_t size)
|
||||
{
|
||||
if (png_ptr == NULL)
|
||||
return;
|
||||
|
||||
if (size == 0 || size > PNG_UINT_31_MAX)
|
||||
if (size == 0 ||
|
||||
size > (png_ptr->read_struct ? ZLIB_IO_MAX : PNG_UINT_31_MAX))
|
||||
png_error(png_ptr, "invalid compression buffer size");
|
||||
|
||||
# if (defined PNG_SEQUENTIAL_READ_SUPPORTED) || defined PNG_WRITE_SUPPORTED
|
||||
png_ptr->IDAT_size = (uInt)/*SAFE*/size;
|
||||
png_ptr->IDAT_size = (png_uint_32)/*SAFE*/size;
|
||||
# endif /* SEQUENTIAL_READ || WRITE */
|
||||
}
|
||||
|
||||
|
||||
@ -576,7 +576,7 @@ struct png_struct_def
|
||||
#endif
|
||||
|
||||
#if defined(PNG_SEQUENTIAL_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
|
||||
uInt IDAT_size; /* limit on IDAT read and write IDAT size */
|
||||
png_uint_32 IDAT_size; /* limit on IDAT read and write IDAT size */
|
||||
#endif /* SEQUENTIAL_READ || WRITE */
|
||||
|
||||
/* ERROR HANDLING */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user