diff options
Diffstat (limited to 'coders/png.c')
-rw-r--r-- | coders/png.c | 327 |
1 files changed, 253 insertions, 74 deletions
diff --git a/coders/png.c b/coders/png.c index 0b79fc3..a13ec35 100644 --- a/coders/png.c +++ b/coders/png.c @@ -1,5 +1,5 @@ /* -% Copyright (C) 2003-2022 GraphicsMagick Group +% Copyright (C) 2003-2023 GraphicsMagick Group % Copyright (C) 2002 ImageMagick Studio % Copyright 1991-1999 E. I. du Pont de Nemours and Company % @@ -679,6 +679,28 @@ static void LogPNGChunk(int logging, png_byte const * type, size_t length) } #endif +/* + Use a macro to report exceptions (rather than calling libpng's + png_error()) for exceptions thrown from this module. + + This provides useful file/line information as well as allowing code + analyzers to have a more accurate idea of what is going on. +*/ +#undef png_error +#define png_error(png_ptr,error_message) \ + do \ + { \ + Image * \ + _image; \ + \ + _image=(Image *) png_get_error_ptr(png_ptr); \ + (void) LogMagickEvent(CoderEvent,GetMagickModule(), \ + " error: %.1024s", error_message); \ + (void) ThrowException2(&_image->exception,CoderError, \ + error_message,_image->filename); \ + longjmp(png_jmpbuf(png_ptr),1); \ + } while(0) + #if PNG_LIBPNG_VER > 10011 /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -786,20 +808,20 @@ static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length) *image; image=(Image *) png_get_io_ptr(png_ptr); - if (length) + if (length > 0) { size_t check; if (length > 0x7fffffff) png_warning(png_ptr, "chunk length > 2G"); - check=ReadBlob(image,(size_t) length,(char *) data); - if (check != (size_t) length) + check=ReadBlob(image, length,(char *) data); + if (check != length) { char msg[MaxTextExtent]; - (void) sprintf(msg,"Expected %" MAGICK_SIZE_T_F "u bytes;" + (void) snprintf(msg,sizeof(msg),"Expected %" MAGICK_SIZE_T_F "u bytes;" " found %" MAGICK_SIZE_T_F "u bytes", (MAGICK_SIZE_T) length,(MAGICK_SIZE_T) check); png_warning(png_ptr,msg); @@ -1275,6 +1297,7 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info, else { strlcpy(profile_name,&text[ii].key[17],sizeof(profile_name)); + LocaleUpper(profile_name); strlcpy(profile_description,"generic profile, type ", sizeof(profile_description)); strlcat(profile_description,&text[ii].key[17], @@ -1344,13 +1367,15 @@ static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) size_t i; + const size_t app1_hdr_size = MAGICK_JPEG_APP1_EXIF_HEADER_SIZE; + image=(Image *) png_get_user_chunk_ptr(ping); if (image->logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " recognized eXIf chunk"); + " recognized eXIf chunk"); - profile=MagickAllocateMemory(unsigned char *,chunk->size+6); + profile=MagickAllocateMemory(unsigned char *,chunk->size+app1_hdr_size); if (profile == (unsigned char *) NULL) { @@ -1361,26 +1386,22 @@ static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) p=profile; - /* Stored profile must start with "Exif\0\0" */ - *p++ ='E'; - *p++ ='x'; - *p++ ='i'; - *p++ ='f'; - *p++ ='\0'; - *p++ ='\0'; + /* Stored profile should start with JPEG APP1 "Exif\0\0" header */ + (void) memcpy(p,MAGICK_JPEG_APP1_EXIF_HEADER,app1_hdr_size); + p += app1_hdr_size; i=0; s=chunk->data; - if (chunk->size > 6 && - (s[0] == 'E' || s[1] == 'x' || s[2] == 'i' || - s[3] == 'f' || s[4] == '\0' || s[5] == '\0')) + if (chunk->size > app1_hdr_size && + (memcmp((const void *) s,(const void *) MAGICK_JPEG_APP1_EXIF_HEADER, + app1_hdr_size) == 0)) { /* Skip over "Exif\0\0" if already present */ - i=6; - s += 6; + i=app1_hdr_size; + s += app1_hdr_size; } /* copy chunk->data to profile */ @@ -1426,7 +1447,7 @@ static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) return(-1); /* Error return */ (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " recognized caNv chunk"); + " recognized caNv chunk"); image=(Image *) png_get_user_chunk_ptr(ping); @@ -1439,7 +1460,7 @@ static int read_user_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) } (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " unrecognized user chunk"); + " unrecognized user chunk: %s", chunk->name); return(0); /* Did not recognize */ } @@ -1506,6 +1527,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, ping_rowbytes, row_offset; + unsigned int + ping_file_depth; + int logging, num_text, @@ -1513,11 +1537,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, pass, ping_bit_depth, ping_colortype, - ping_file_depth, ping_interlace_method, ping_compression_method, ping_filter_method, - ping_num_trans; + ping_num_trans=0; LongPixelPacket transparent_color; @@ -1544,7 +1567,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, *q; #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - png_byte unused_chunks[]= + static const png_byte unused_chunks[]= { 104, 73, 83, 84, '\0', /* hIST */ 105, 84, 88, 116, '\0', /* iTXt */ @@ -1552,6 +1575,9 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, 115, 67, 65, 76, '\0', /* sCAL */ 115, 80, 76, 84, '\0', /* sPLT */ 116, 73, 77, 69, '\0', /* tIME */ +#ifdef PNG_READ_eXIf_SUPPORTED /* Enforce custom eXIf processing to override default one. */ + 101, 88, 73, 102, '\0', /* eXIf*/ +#endif #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */ /* ignore the APNG chunks */ 97, 99, 84, 76, '\0', /* acTL */ @@ -1629,8 +1655,16 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, } if (image) { - DestroyImage(image); + /* Image is part of mng_info->image list (see above) */ + DestroyImageList(image); image=(Image *) NULL; + mng_info->image=(Image *) NULL; + } + /* We are not aware that the following case ever happens */ + if (mng_info->image) + { + DestroyImageList(mng_info->image); + mng_info->image=(Image *) NULL; } return(image); } @@ -1774,6 +1808,25 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, &ping_filter_method); +#if (defined(__clang_analyzer__) || defined(__COVERITY__)) + /* + png_get_IHDR() should already have thrown an exception but + Coverity and Clang Analyzer can not see that since it is library + code. + */ + if (ping_bit_depth != 1 && + ping_bit_depth != 2 && + ping_bit_depth != 4 && + ping_bit_depth != 8 && + ping_bit_depth != 16) + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " libpng-%.1024s error: %.1024s", + PNG_LIBPNG_VER_STRING, "Bit depth is not valid"); + longjmp(png_jmpbuf(ping),1); + } +#endif /* #if (defined(__clang_analyzer__) || defined(__COVERITY__)) */ + #if (QuantumDepth == 8) if (ping_bit_depth > 8) { @@ -1795,7 +1848,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, image->depth=8; #endif - ping_file_depth = ping_bit_depth; + ping_file_depth = (unsigned int) ping_bit_depth; /* Save bit-depth and color-type in case we later want to write a PNG00 */ { @@ -1907,7 +1960,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, intent+1); } } -#endif +#endif /* if defined(PNG_READ_sRGB_SUPPORTED) */ { double file_gamma; @@ -2044,7 +2097,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (mng_info->global_trns_length > mng_info->global_plte_length) png_error(ping, "global tRNS has more entries" - " than global PLTE"); + " than global PLTE"); png_set_tRNS(ping,ping_info,mng_info->global_trns, (int) mng_info->global_trns_length,NULL); } @@ -2058,6 +2111,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, png_color_16 background; + background.index=0; #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED if (mng_info->have_saved_bkgd_index) background.index=mng_info->saved_bkgd_index; @@ -2150,16 +2204,17 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #endif if (png_get_valid(ping, ping_info, PNG_INFO_tRNS) && - (ping_trans_color != (png_color_16p) NULL)) + (ping_trans_color != (png_color_16p) NULL) && + (((unsigned int) ping_file_depth) <= MaxColormapSize)) { - int + unsigned int bit_mask; if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG tRNS chunk."); - bit_mask = (1U << ping_file_depth) - 1; + bit_mask = MaxValueGivenBits(ping_file_depth); /* Image has a transparent background. @@ -2181,13 +2236,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #endif transparent_color.opacity=(unsigned long) ( ping_trans_color->gray * - (65535L/((1UL << ping_file_depth)-1))); + (65535L/MaxValueGivenBits(ping_file_depth))); /* Coverity 381876 Division or modulo by zero (DIVIDE_BY_ZERO) */ #if (QuantumDepth == 8) else transparent_color.opacity=(unsigned long) ( - (ping_trans_color->gray * 65535L)/ - ((1UL << ping_file_depth)-1)); + (ping_trans_color->gray * 65535UL)/ + MaxValueGivenBits(ping_file_depth)); #endif if (logging != MagickFalse) { @@ -2234,12 +2289,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, image->compression=ZipCompression; image->columns=ping_width; image->rows=ping_height; - if ((ping_colortype == PNG_COLOR_TYPE_PALETTE) || - (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) || - (ping_colortype == PNG_COLOR_TYPE_GRAY)) + if (((unsigned int) ping_file_depth <= MaxColormapSize) && + ((ping_colortype == PNG_COLOR_TYPE_PALETTE) || + (ping_colortype == PNG_COLOR_TYPE_GRAY_ALPHA) || + (ping_colortype == PNG_COLOR_TYPE_GRAY))) { image->storage_class=PseudoClass; - image->colors=1U << ping_file_depth; + image->colors=1U << ping_file_depth; /* Coverity (#1-3 of 3): Bad bit shift operation (BAD_SHIFT) */ #if (QuantumDepth == 8) if (image->colors > 256) image->colors=256; @@ -2292,7 +2348,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, unsigned long scale; - scale=(MaxRGB/((1U << ping_file_depth)-1)); + scale=(MaxRGB/MaxValueGivenBits(ping_file_depth)); if (scale < 1) scale=1; for (i=0; i < (long) image->colors; i++) @@ -2939,6 +2995,28 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, UnlockSemaphoreInfo(png_semaphore); #endif + /* + Retrieve image orientation from EXIF (if present) and store in + image. + */ + { + const ImageAttribute + *attribute; + + attribute = GetImageAttribute(image,"EXIF:Orientation"); + if ((attribute != (const ImageAttribute *) NULL) && + (attribute->value != (char *) NULL)) + { + int + orientation; + + orientation = MagickAtoI(attribute->value); + if ((orientation > UndefinedOrientation) && + (orientation <= LeftBottomOrientation)) + image->orientation=(OrientationType) orientation; + } + } + if (logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit ReadOnePNGImage()"); @@ -3251,7 +3329,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, break; type[0]='\0'; - (void) strcat(type,"errr"); + (void) strlcat(type,"errr",sizeof(type)); length=(size_t) ReadBlobMSBLong(image); count=(unsigned int) ReadBlob(image,4,type); if (count != 4) @@ -3262,6 +3340,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, "chunk count is zero"); ThrowException(exception,CorruptImageError, UnexpectedEndOfFile,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image*)NULL); } if (logging) @@ -3285,6 +3364,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, (MAGICK_SIZE_T) length); ThrowException(exception,CorruptImageError, ImproperImageHeader,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image*)NULL); } if (length > (size_t) blob_size) @@ -3300,6 +3380,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, blob_size); ThrowException(exception,CorruptImageError, ImproperImageHeader,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image*)NULL); } @@ -3315,6 +3396,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " Could not allocate chunk memory"); ThrowException(exception,ResourceLimitError, MemoryAllocationFailed,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image*)NULL); } if (ReadBlob(image,length,chunk) != length) @@ -3325,6 +3407,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " chunk reading was incomplete"); ThrowException(exception,CorruptImageError, InsufficientImageDataInFile,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image*)NULL); } p=chunk; @@ -3393,6 +3476,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, ImproperImageHeader,image->filename); DestroyJNG(chunk,&color_image,&color_image_info, &alpha_image,&alpha_image_info); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } @@ -3410,6 +3494,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, InsufficientImageDataInFile,image->filename); DestroyJNG(chunk,&color_image,&color_image_info, &alpha_image,&alpha_image_info); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } @@ -3440,6 +3525,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " could not allocate color_image_info"); ThrowException(exception,ResourceLimitError, MemoryAllocationFailed,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } GetImageInfo(color_image_info); @@ -3452,6 +3538,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " could not allocate color_image"); ThrowException(exception,ResourceLimitError, MemoryAllocationFailed,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } if (logging) @@ -3467,6 +3554,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, &alpha_image,&alpha_image_info); (void) LogMagickEvent(CoderEvent,GetMagickModule(), " could not open color_image blob"); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } @@ -3484,6 +3572,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, &alpha_image,&alpha_image_info); ThrowException(exception,CorruptImageError,ImproperImageHeader, image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } @@ -3497,6 +3586,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " could not allocate alpha_image_info (returning NULL)"); ThrowException(exception,ResourceLimitError, MemoryAllocationFailed,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } GetImageInfo(alpha_image_info); @@ -3509,6 +3599,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " could not allocate alpha_image (returning NULL)"); ThrowException(exception,ResourceLimitError, MemoryAllocationFailed,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } if (logging) @@ -3523,6 +3614,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, &alpha_image,&alpha_image_info); (void) LogMagickEvent(CoderEvent,GetMagickModule(), " could not open alpha_image blob (returning NULL)"); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } if (jng_alpha_compression_method == 0) @@ -3799,6 +3891,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, } DestroyImageList(color_image); color_image=(Image *) NULL; + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return (Image *) NULL; } @@ -3830,6 +3923,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, */ DestroyJNG(/*chunk*/ NULL,&color_image,&color_image_info, &alpha_image,&alpha_image_info); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return (Image *) NULL; } @@ -3851,6 +3945,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, DestroyImageList(jng_image); ThrowException(exception,CorruptImageError, ImproperImageHeader,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } if ((image->columns != jng_image->columns) || @@ -3867,6 +3962,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, DestroyImage(jng_image); ThrowException(exception,CorruptImageError, ImproperImageHeader,image->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } if (logging) @@ -3893,6 +3989,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, "Failed to transfer JPEG scanlines"); DestroyJNG(NULL,&color_image,&color_image_info, &alpha_image,&alpha_image_info); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadOneJNGImage()"); return ((Image *)NULL); } if (alpha_image != (Image *)NULL && !image_info->ping) @@ -4151,6 +4248,7 @@ static Image *ReadJNGImage(const ImageInfo *image_info, have_mng_structure=MagickTrue; mng_info->image=image; + (void) LogMagickEvent(CoderEvent,GetMagickModule()," calling ReadOneJNGImage()"); image=ReadOneJNGImage(mng_info,image_info,exception); if (image == (Image *) NULL || image->columns == 0 || image->rows == 0) { @@ -4187,8 +4285,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, page_geometry[MaxTextExtent]; Image - *image, - *previous; + *image; int have_mng_structure; @@ -4284,6 +4381,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, assert(exception->signature == MagickSignature); logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()"); image=AllocateImage(image_info); + (void) LogMagickEvent(CoderEvent,GetMagickModule(),"ALLOCATED %p", image); mng_info=(MngInfo *) NULL; status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); if (status == MagickFalse) @@ -4366,7 +4464,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, Read a new chunk. */ type[0]='\0'; - (void) strcat(type,"errr"); + (void) strlcat(type,"errr",sizeof(type)); length=(size_t) ReadBlobMSBLong(image); count=ReadBlob(image,4,type); if (count != 4) @@ -4528,7 +4626,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info, */ AllocateNextImage(image_info,image); if (image->next == (Image *) NULL) - return((Image *) NULL); + { + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); + return((Image *) NULL); + } image=SyncNextImageInList(image); mng_info->image=image; } @@ -4969,6 +5070,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, { DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } image=SyncNextImageInList(image); @@ -5005,6 +5107,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, MagickFreeMemory(chunk); DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } if (logging) @@ -5573,6 +5676,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, { DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } image=SyncNextImageInList(image); @@ -5625,6 +5729,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, { DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } image=SyncNextImageInList(image); @@ -5670,6 +5775,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, { DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } image=SyncNextImageInList(image); @@ -5712,23 +5818,35 @@ static Image *ReadMNGImage(const ImageInfo *image_info, (void) SeekBlob(image,-((long) length+12),SEEK_CUR); } - previous=image; mng_info->image=image; mng_info->mng_type=mng_type; mng_info->object_id=object_id; if (!memcmp(type,mng_IHDR,4)) - image=ReadOnePNGImage(mng_info,image_info,exception); + { + (void) LogMagickEvent(CoderEvent,GetMagickModule()," calling ReadOnePNGImage()"); + /* If NULL is returned, then mng_info->image was already freed by ReadOnePNGImage! */ + image=ReadOnePNGImage(mng_info,image_info,exception); + } #if defined(JNG_SUPPORTED) else - image=ReadOneJNGImage(mng_info,image_info,exception); + { + (void) LogMagickEvent(CoderEvent,GetMagickModule()," calling ReadOneJNGImage()"); + /* ReadOneJNGImage() does not free mng_info->image as ReadOnePNGImage() does! */ + image=ReadOneJNGImage(mng_info,image_info,exception); + } #endif if (image == (Image *) NULL) { - CloseBlob(previous); - DestroyImageList(previous); + if (mng_info->image != (Image *) NULL) + { + CloseBlob(mng_info->image); + DestroyImageList(mng_info->image); + mng_info->image=(Image *) NULL; + } MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } if (image->columns == 0 || image->rows == 0) @@ -5736,8 +5854,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info, CloseBlob(image); DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } + mng_info->image=image; if (mng_type) @@ -5750,6 +5870,35 @@ static Image *ReadMNGImage(const ImageInfo *image_info, magnify the image. http://www.libpng.org/pub/mng/spec/mng-1.0-20010209-pdg.html#mng-MAGN + + Extracted summary of magnification options: + + X_method: 1 byte + 0 or omitted: No magnification + 1: Pixel replication of color and alpha samples. + 2: Magnified intervals with linear interpolation of + color and alpha samples. + 3: Magnified intervals with replication of color and + alpha samples from the closest pixel. + 4: Magnified intervals with linear interpolation of + color samples and replication of alpha samples from + the closest pixel. + 5: Magnified intervals with linear interpolation of + alpha samples and replication of color samples from + the closest pixel. + MX: 2 bytes. X magnification factor, range 1-65535. If + omitted, MX=1. Ignored if X_method is 0 and assumed to + be 1. + MY: 2 bytes. Y magnification factor. If omitted, MY=MX. + ML: 2 bytes. Left X magnification factor. If omitted, ML=MX. + MR: 2 bytes. Right X magnification factor. If omitted, MR=MX. + MT: 2 bytes. Top Y magnification factor. If omitted, MT=MY. + Ignored if Y_method is 0 and assumed to be 1. + MB: 2 bytes. Bottom Y magnification factor. If omitted, + MB=MY. + Y_method: 1 byte. If omitted, Y_method is the same as X_method. + + */ if (((mng_info->magn_methx > 0) && (mng_info->magn_methx <= 5)) && ((mng_info->magn_methy > 0) && (mng_info->magn_methy <= 5))) @@ -5876,6 +6025,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, { DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } @@ -5955,7 +6105,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info, } n=GetImagePixels(image,0,0,image->columns,1); if(n == (PixelPacket *) NULL) - return ((Image *) NULL); + { + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); + return ((Image *) NULL); + } (void) memcpy(next,n,row_length); for (y=0; y < (long) image->rows; y++) { @@ -6044,11 +6197,20 @@ static Image *ReadMNGImage(const ImageInfo *image_info, *q=(*n); if (magn_methy == 5) { - (*q).opacity=(QM) ( + if (i == 0) + { + /* Copy */ + (*q).opacity=(*p).opacity; + } + else + { + /* Interpolate */ + (*q).opacity=(QM) ( ((long) (2*i*((*n).opacity -(*p).opacity)+m))/ ((long) (m*2))+ (*p).opacity); + } } } n++; @@ -6154,11 +6316,19 @@ static Image *ReadMNGImage(const ImageInfo *image_info, *q=(*n); if (magn_methx == 5) { - /* Interpolate */ - (*q).opacity=(QM) ((2*i*((*n).opacity /* oss-fuzz 31109 buffer over-read */ - -(*p).opacity)+m)/ - ((long) (m*2)) - +(*p).opacity); + if (i == 0) + { + /* Copy */ + (*q).opacity=(*p).opacity; + } + else + { + /* Interpolate */ + (*q).opacity=(QM) ((2*i*((*n).opacity + -(*p).opacity)+m)/ + ((long) (m*2)) + +(*p).opacity); + } } } q++; @@ -6325,6 +6495,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, if (logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Allocation failed, returning NULL."); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } image=SyncNextImageInList(image); @@ -6349,7 +6520,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, { image_count++; #if 0 - /* This code triggers and fails to reliease memory in oss-fuzz 8710 */ + /* This code triggers and fails to release memory in oss-fuzz 8710 */ if (image_count > 10*mng_info->image_found) { if (logging) @@ -6360,6 +6531,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, "Linked list is corrupted," " beginning of list not found", image_info->filename); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } #endif @@ -6396,6 +6568,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, if (image != (Image *) NULL) DestroyImageList(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } @@ -6459,6 +6632,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info, if (next_image == (Image *) NULL) { MngInfoFreeStruct(mng_info,&have_mng_structure); + (void) LogMagickEvent(CoderEvent,GetMagickModule()," return NULL from ReadMNGImage()"); return((Image *) NULL); } image=next_image; @@ -6931,16 +7105,16 @@ png_write_raw_profile(const ImageInfo *image_info,png_struct *ping, text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80); #endif text[0].key[0]='\0'; - (void) strcat(text[0].key, "Raw profile type "); + (void) strlcat(text[0].key, "Raw profile type ", 80); (void) strncat(text[0].key, (const char *) profile_type, 61); sp=profile_data; dp=text[0].text; *dp++='\n'; - (void) strcpy(dp,(const char *) profile_description); - dp+=description_length; + (void) strlcpy(dp,(const char *) profile_description,(allocated_length-(dp-text[0].text))); + dp+=strlen(dp); *dp++='\n'; - (void) sprintf(dp,"%8lu ",(unsigned long)length); - dp+=8; + (void) snprintf(dp,(allocated_length-(dp-text[0].text)),"%8lu ",(unsigned long)length); + dp+=strlen(dp); for (i=0; i < (long) length; i++) { if (i%36 == 0) @@ -7059,7 +7233,7 @@ static MagickPassFail WriteOnePNGImage(MngInfo *mng_info, */ gm_vers=MagickLibVersionText; #ifdef HasLCMS - (void) sprintf(lcms_vers,"%.4d",LCMS_VERSION); + (void) snprintf(lcms_vers,sizeof(lcms_vers),"%.4d",LCMS_VERSION); #endif libpng_runv=png_get_libpng_ver(NULL); libpng_vers=PNG_LIBPNG_VER_STRING; @@ -8034,20 +8208,20 @@ static MagickPassFail WriteOnePNGImage(MngInfo *mng_info, if (image->units == PixelsPerInchResolution) { unit_type=PNG_RESOLUTION_METER; - x_resolution=(png_uint_32) ((100.0*image->x_resolution+0.5)/2.54); - y_resolution=(png_uint_32) ((100.0*image->y_resolution+0.5)/2.54); + x_resolution=(png_uint_32) MagickDoubleToUInt((100.0*image->x_resolution+0.5)/2.54); + y_resolution=(png_uint_32) MagickDoubleToUInt((100.0*image->y_resolution+0.5)/2.54); } else if (image->units == PixelsPerCentimeterResolution) { unit_type=PNG_RESOLUTION_METER; - x_resolution=(png_uint_32) (100.0*image->x_resolution+0.5); - y_resolution=(png_uint_32) (100.0*image->y_resolution+0.5); + x_resolution=(png_uint_32) MagickDoubleToUInt(100.0*image->x_resolution+0.5); + y_resolution=(png_uint_32) MagickDoubleToUInt(100.0*image->y_resolution+0.5); } else { unit_type=PNG_RESOLUTION_UNKNOWN; - x_resolution=(png_uint_32) image->x_resolution; - y_resolution=(png_uint_32) image->y_resolution; + x_resolution=(png_uint_32) MagickDoubleToUInt(image->x_resolution); + y_resolution=(png_uint_32) MagickDoubleToUInt(image->y_resolution); } png_set_pHYs(ping,ping_info,x_resolution,y_resolution,unit_type); @@ -8057,9 +8231,9 @@ static MagickPassFail WriteOnePNGImage(MngInfo *mng_info, (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up pHYs chunk"); (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " x_resolution=%lu",(unsigned long) x_resolution); + " x_resolution=%u",(unsigned int) x_resolution); (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " y_resolution=%lu",(unsigned long) y_resolution); + " y_resolution=%u",(unsigned int) y_resolution); (void) LogMagickEvent(CoderEvent,GetMagickModule(), " unit_type=%lu",(unsigned long) unit_type); } @@ -8090,17 +8264,22 @@ static MagickPassFail WriteOnePNGImage(MngInfo *mng_info, if (profile_iterator) { const char - *profile_name; + *profile_name_uc; const unsigned char *profile_info; + char + profile_name[MaxTextExtent]; + size_t profile_length; - while (NextImageProfile(profile_iterator,&profile_name,&profile_info, + while (NextImageProfile(profile_iterator,&profile_name_uc,&profile_info, &profile_length) != MagickFail) { + (void) strlcpy(profile_name, profile_name_uc, sizeof(profile_name)); + LocaleLower(profile_name); if (LocaleCompare(profile_name,"ICM") == 0) { #if defined(PNG_WRITE_iCCP_SUPPORTED) @@ -8196,7 +8375,7 @@ static MagickPassFail WriteOnePNGImage(MngInfo *mng_info, */ if (logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Setting up gAMA chunk"); + " Setting up gAMA chunk gamma=%f", image->gamma); png_set_gAMA(ping,ping_info,image->gamma); } if (!mng_info->have_write_global_chrm && |