diff --git a/ANNOUNCE b/ANNOUNCE index d56a17dd..48347b91 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ -Libpng 1.2.43beta04 - February 9, 2010 +Libpng 1.2.43beta05 - February 13, 2010 This is not intended to be a public release. It will be replaced within a few weeks by a public version or by another test version. @@ -9,36 +9,36 @@ Files available for download: Source files with LF line endings (for Unix/Linux) and with a "configure" script - libpng-1.2.43beta04.tar.xz (LZMA-compressed, recommended) - libpng-1.2.43beta04.tar.gz - libpng-1.2.43beta04.tar.bz2 + libpng-1.2.43beta05.tar.xz (LZMA-compressed, recommended) + libpng-1.2.43beta05.tar.gz + libpng-1.2.43beta05.tar.bz2 Source files with LF line endings (for Unix/Linux) without the "configure" script - libpng-1.2.43beta04-no-config.tar.xz (LZMA-compressed, recommended) - libpng-1.2.43beta04-no-config.tar.gz - libpng-1.2.43beta04-no-config.tar.bz2 + libpng-1.2.43beta05-no-config.tar.xz (LZMA-compressed, recommended) + libpng-1.2.43beta05-no-config.tar.gz + libpng-1.2.43beta05-no-config.tar.bz2 Source files with CRLF line endings (for Windows), without the "configure" script - lp1243b04.zip - lp1243b04.7z - lp1243b04.tar.bz2 + lp1243b05.zip + lp1243b05.7z + lp1243b05.tar.bz2 Project files - libpng-1.2.43beta04-project-netware.zip - libpng-1.2.43beta04-project-wince.zip + libpng-1.2.43beta05-project-netware.zip + libpng-1.2.43beta05-project-wince.zip Other information: - libpng-1.2.43beta04-README.txt - libpng-1.2.43beta04-KNOWNBUGS.txt - libpng-1.2.43beta04-LICENSE.txt - libpng-1.2.43beta04-Y2K-compliance.txt - libpng-1.2.43beta04-[previous version]-diff.txt + libpng-1.2.43beta05-README.txt + libpng-1.2.43beta05-KNOWNBUGS.txt + libpng-1.2.43beta05-LICENSE.txt + libpng-1.2.43beta05-Y2K-compliance.txt + libpng-1.2.43beta05-[previous version]-diff.txt Changes since the last public release (1.2.42): @@ -58,13 +58,16 @@ version 1.2.43beta03 [February 6, 2010] Backported fast png_push_save_buffer() algorithm from libpng-1.4.1 version 1.2.43beta04 [February 8, 2010] - Fixed incorrect test in new png_push_save_buffer() code. Reverted recent changes to png_push_save-buffer(). Removed PNGAPI declaration of png_calloc() and png_write_sig() in 1ibpng-1.2.X, introduced by mistake in libpng-1.2.41. - Return allocated "old_buffer" in png_push_save_buffer() before png_error(). + Return allocated "old_buffer" in png_push_save_buffer() before png_error(), + to avoid a potential memory leak. -version 1.0.53rc01 and 1.2.43rc01 [February 9, 2010] +version 1.2.43beta05 [February 8, 2010] + Ported rewritten png_decompress_chunk() by John Bowler from libpng-1.4.1. + +version 1.0.53rc01 and 1.2.43rc01 [February 13, 2010] No changes. Send comments/corrections/commendations to png-mng-implement at lists.sf.net diff --git a/CHANGES b/CHANGES index 415a67bf..fbde67a0 100644 --- a/CHANGES +++ b/CHANGES @@ -2660,13 +2660,16 @@ version 1.2.43beta03 [February 6, 2010] Backported some cosmetic changes from libpng-1.4.1. version 1.2.43beta04 [February 8, 2010] - Fixed incorrect test in new png_push_save_buffer() code. Reverted recent changes to png_push_save-buffer(). Removed PNGAPI declaration of png_calloc() and png_write_sig() in 1ibpng-1.2.X, introduced by mistake in libpng-1.2.41. - Return allocated "old_buffer" in png_push_save_buffer() before png_error(). + Return allocated "old_buffer" in png_push_save_buffer() before png_error() + to avoid a potential memory leak. -version 1.0.53rc01 and 1.2.43rc01 [February 9, 2010] +version 1.2.43beta05 [February 8, 2010] + Ported rewritten png_decompress_chunk() by John Bowler from libpng-1.4.1. + +version 1.0.53rc01 and 1.2.43rc01 [February 13, 2010] No changes. Send comments/corrections/commendations to png-mng-implement at lists.sf.net diff --git a/pngrutil.c b/pngrutil.c index a270aa34..14d532af 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.2.43 [February 9, 2010] + * Last changed in libpng 1.2.43 [February 13, 2010] * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -218,70 +218,93 @@ png_crc_error(png_structp png_ptr) #if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ defined(PNG_READ_iCCP_SUPPORTED) -png_size_t -png_measure_decompressed_chunk(png_structp png_ptr, int comp_type, - png_size_t chunklength, png_size_t prefix_size) +static png_size_t +png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size, + png_bytep output, png_size_t output_size) { - png_charp text; - png_charp test = "X"; - png_size_t text_size = 0; + png_size_t count = 0; - if (comp_type == PNG_COMPRESSION_TYPE_BASE) + png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */ + png_ptr->zstream.avail_in = size; + + while (1) { - int ret = Z_OK; + int ret, avail; - png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size); - png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); + /* Reset the output buffer each time round - we empty it + * after every inflate call. + */ png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.avail_out = png_ptr->zbuf_size; - text = NULL; + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; - while (png_ptr->zstream.avail_in) + /* First copy/count any new output - but only if we didn't + * get an error code. + */ + if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) { - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - break; - } - if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) - { - if (text == NULL) /* Initialize the decompression buffer */ - { - text_size = prefix_size + - png_ptr->zbuf_size - png_ptr->zstream.avail_out; - - text=test; - } - else /* Enlarge the decompression buffer */ - { - text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; -#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - if (png_ptr->user_chunk_malloc_max && - (text_size >= png_ptr->user_chunk_malloc_max - 1)) -#else - if ((PNG_USER_CHUNK_MALLOC_MAX > 0) && - text_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) -#endif - return 0; - } - } - if (ret == Z_STREAM_END) - break; - - else - { - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } + if (output != 0 && output_size > count) + { + int copy = output_size - count; + if (avail < copy) copy = avail; + png_memcpy(output + count, png_ptr->zbuf, copy); + } + count += avail; } - inflateReset(&png_ptr->zstream); + if (ret == Z_OK) + continue; + + /* Termination conditions - always reset the zstream, it + * must be left in inflateInit state. + */ png_ptr->zstream.avail_in = 0; + inflateReset(&png_ptr->zstream); + + if (ret == Z_STREAM_END) + return count; /* NOTE: may be zero. */ + + /* Now handle the error codes - the API always returns 0 + * and the error message is dumped into the uncompressed + * buffer if available. + */ + { + char *msg, umsg[52]; + if (png_ptr->zstream.msg != 0) + msg = png_ptr->zstream.msg; + else + { +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + switch (ret) + { + case Z_BUF_ERROR: + msg = "Buffer error in compressed datastream in %s chunk"; + break; + case Z_DATA_ERROR: + msg = "Data error in compressed datastream in %s chunk"; + break; + default: + msg = "Incomplete compressed datastream in %s chunk"; + break; + } + + png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); + msg = umsg; +#else + msg = "Damaged compressed datastream in chunk other than IDAT"; +#endif + } + + png_warning(png_ptr, msg); + } + + /* 0 means an error - notice that this code simple ignores + * zero length compressed chunks as a result. + */ + return 0; } - return text_size; } /* @@ -296,164 +319,104 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, png_size_t chunklength, png_size_t prefix_size, png_size_t *newlength) { - static PNG_CONST char msg[] = "Error decoding compressed chunk"; - png_charp text; - png_size_t text_size; - png_size_t expanded_size; - - expanded_size= png_measure_decompressed_chunk(png_ptr, comp_type, - chunklength, prefix_size); - if (expanded_size == 0) + /* The caller should guarantee this */ + if (prefix_size > chunklength) { - *newlength=0; - return; + /* The recovery is to delete the chunk. */ + png_warning(png_ptr, "invalid chunklength"); + prefix_size = 0; /* To delete everything */ } - if (comp_type == PNG_COMPRESSION_TYPE_BASE) + else if (comp_type == PNG_COMPRESSION_TYPE_BASE) { - int ret = Z_OK; - png_size_t buffer_size; + png_size_t expanded_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + 0/*output*/, 0/*output size*/); - png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size); - png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - text_size = 0; - text = NULL; - buffer_size = 0; - - while (png_ptr->zstream.avail_in) - { - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - if (png_ptr->zstream.msg != NULL) - png_warning(png_ptr, png_ptr->zstream.msg); - else - png_warning(png_ptr, msg); - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - - if (text == NULL) - { - text_size = prefix_size + png_sizeof(msg) + 1; - text = (png_charp)png_malloc_warn(png_ptr, text_size); - if (text == NULL) - { - png_error(png_ptr, - "Not enough memory to decompress chunk"); - text_size = 0; - break; - } - png_memcpy(text, png_ptr->chunkdata, prefix_size); - } - - text[text_size - 1] = 0x00; - - /* Copy what we can of the error message into the text chunk */ - text_size = (png_size_t)(chunklength - - (text - png_ptr->chunkdata) - 1); - - if (text_size > png_sizeof(msg)) - text_size = png_sizeof(msg); - - png_memcpy(text + prefix_size, msg, text_size); - buffer_size = text_size; - break; - } - if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) - { - if (text == NULL) /* Initialize the decompression buffer */ - { - text_size = expanded_size; - - text = (png_charp)png_malloc_warn(png_ptr, text_size + 1); - if (text == NULL) - { - png_error(png_ptr, - "Not enough memory to decompress chunk."); - text_size = 0; - break; - } - png_memcpy(text + prefix_size, png_ptr->zbuf, - text_size - prefix_size); - png_memcpy(text, png_ptr->chunkdata, prefix_size); - *(text + text_size) = 0x00; - buffer_size = text_size; - } - } - if (ret == Z_STREAM_END) - break; - - else - { - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - } - - if (ret != Z_STREAM_END) - { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) - char umsg[52]; - - if (ret == Z_BUF_ERROR) - png_snprintf(umsg, 52, - "Buffer error in compressed datastream in %s chunk", - png_ptr->chunk_name); - - else if (ret == Z_DATA_ERROR) - png_snprintf(umsg, 52, - "Data error in compressed datastream in %s chunk", - png_ptr->chunk_name); - - else - png_snprintf(umsg, 52, - "Incomplete compressed datastream in %s chunk", - png_ptr->chunk_name); - - png_warning(png_ptr, umsg); + /* Now check the limits on this chunk - if the limit fails the + * compressed data will be removed, the prefix will remain. + */ +#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max && + (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1)) #else - png_warning(png_ptr, - "Incomplete compressed datastream in chunk other than IDAT"); + if ((PNG_USER_CHUNK_MALLOC_MAX > 0) && + prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) #endif - text_size = prefix_size; - if (text == NULL) + png_warning(png_ptr, "Exceeded size limit while expanding chunk"); + + /* If the size is zero either there was an error and a message + * has already been output (warning) or the size really is zero + * and we have nothing to do - the code will exit through the + * error case below. + */ + else if (expanded_size > 0) + { + /* Success (maybe) - really uncompress the chunk. */ + png_size_t new_size = 0; + png_charp text = png_malloc_warn(png_ptr, + prefix_size + expanded_size + 1); + + if (text != NULL) { - text = (png_charp)png_malloc_warn(png_ptr, text_size+1); - if (text == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_error(png_ptr, "Not enough memory for text"); - } - png_memcpy(text, png_ptr->chunkdata, prefix_size); - } - *(text + text_size) = 0x00; + png_memcpy(text, png_ptr->chunkdata, prefix_size); + new_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + (png_bytep)(text + prefix_size), expanded_size); + text[prefix_size + expanded_size] = 0; /* just in case */ + + if (new_size == expanded_size) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + *newlength = prefix_size + expanded_size; + return; /* The success return! */ + } + + png_warning(png_ptr, "png_inflate logic error"); + png_free(png_ptr, text); + } + else + png_warning(png_ptr, "Not enough memory to decompress chunk."); } - - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - *newlength=text_size; } + else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ { -#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) char umsg[50]; - png_snprintf(umsg, 50, "Unknown zTXt compression type %d", comp_type); +#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) + png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", comp_type); png_warning(png_ptr, umsg); #else png_warning(png_ptr, "Unknown zTXt compression type"); #endif - *(png_ptr->chunkdata + prefix_size) = 0x00; - *newlength = prefix_size; + /* The recovery is to simply drop the data. */ } + + /* Generic error return - leave the prefix, delete the compressed + * data, reallocate the chunkdata to remove the potentially large + * amount of compressed data. + */ + { + png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); + if (text != NULL) + { + if (prefix_size > 0) + png_memcpy(text, png_ptr->chunkdata, prefix_size); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + + /* This is an extra zero in the 'uncompressed' part. */ + *(png_ptr->chunkdata + prefix_size) = 0x00; + } + /* Ignore a malloc error here - it is safe. */ + } + + *newlength = prefix_size; } #endif @@ -3156,7 +3119,7 @@ png_read_finish_row(png_structp png_ptr) { if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || png_ptr->idat_size) - png_warning(png_ptr, "Extra compressed data"); + png_warning(png_ptr, "Extra compressed data."); png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; break; @@ -3178,7 +3141,7 @@ png_read_finish_row(png_structp png_ptr) } if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_warning(png_ptr, "Extra compression data"); + png_warning(png_ptr, "Extra compression data."); inflateReset(&png_ptr->zstream);