GraphicsMagick: WriteOnePNGImage(): Address undefined behavior w...
GraphicsMagick Commits <[email protected]>
| Newsgroups | gmane.comp.video.graphicsmagick.cvs |
|---|---|
| Message-ID | <mailman.4614.1680981562.1789.graphicsmagick-commit@lists.sourceforge.net> |
changeset f462cca796b5 in /hg/GraphicsMagick details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=f462cca796b5 summary: WriteOnePNGImage(): Address undefined behavior while converting floating point resolution to unsigned integer. diffstat: ChangeLog | 7 +- coders/png.c | 16 +- magick/utility-private.h | 7 +- magick/utility.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++ www/Changelog.html | 6 +- 5 files changed, 240 insertions(+), 11 deletions(-) diffs (326 lines): diff -r 90a7c0b86df3 -r f462cca796b5 ChangeLog --- a/ChangeLog Sat Apr 08 12:14:35 2023 -0500 +++ b/ChangeLog Sat Apr 08 14:19:11 2023 -0500 @@ -1,8 +1,13 @@ 2023-04-08 Bob Friesenhahn <[email protected]> + * coders/png.c (WriteOnePNGImage): Address undefined behavior + while converting floating point resolution to unsigned integer. + (SourceForge issue #706 test case 'bug19'); + * magick/utility.c (GetGeometry): Improve geometry parser to validate that parsed double values do not underflow or overflow - when cast to 'unsigned long' or 'long' types. + when cast to 'unsigned long' or 'long' types. (SourceForge issue + #706 test case 'bug11'); * coders/mpc.c (ReadMPCImage): If an attribute appears multiple times in the MPC header, only set it once. diff -r 90a7c0b86df3 -r f462cca796b5 coders/png.c --- a/coders/png.c Sat Apr 08 12:14:35 2023 -0500 +++ b/coders/png.c Sat Apr 08 14:19:11 2023 -0500 @@ -8140,20 +8140,20 @@ 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); @@ -8163,9 +8163,9 @@ (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); } diff -r 90a7c0b86df3 -r f462cca796b5 magick/utility-private.h --- a/magick/utility-private.h Sat Apr 08 12:14:35 2023 -0500 +++ b/magick/utility-private.h Sat Apr 08 14:19:11 2023 -0500 @@ -1,5 +1,5 @@ /* - Copyright (C) 2003 - 2020 GraphicsMagick Group + Copyright (C) 2003 - 2023 GraphicsMagick Group Copyright (C) 2002 ImageMagick Studio Copyright 1991-1999 E. I. du Pont de Nemours and Company @@ -31,7 +31,12 @@ extern MagickExport MagickPassFail MagickAtoUIChk(const char *str, unsigned int *value); extern MagickExport MagickPassFail MagickAtoLChk(const char *str, long *value); extern MagickExport MagickPassFail MagickAtoULChk(const char *str, unsigned long *value); +extern MagickExport unsigned long MagickDoubleToULong(const double dval/*, ExceptionInfo *exception*/) MAGICK_FUNC_CONST; +extern MagickExport unsigned int MagickDoubleToUInt(const double dval/*, ExceptionInfo *exception*/) MAGICK_FUNC_CONST; extern MagickExport long MagickDoubleToLong(const double dval/*, ExceptionInfo *exception*/) MAGICK_FUNC_CONST; +extern MagickExport int MagickDoubleToInt(const double dval/*, ExceptionInfo *exception*/) MAGICK_FUNC_CONST; +extern MagickExport unsigned short int MagickDoubleToUShort(const double dval/*, ExceptionInfo *exception*/) MAGICK_FUNC_CONST; +extern MagickExport short int MagickDoubleToShort(const double dval/*, ExceptionInfo *exception*/) MAGICK_FUNC_CONST; extern MagickExport size_t MagickStripSpacesFromString(char *string), diff -r 90a7c0b86df3 -r f462cca796b5 magick/utility.c --- a/magick/utility.c Sat Apr 08 12:14:35 2023 -0500 +++ b/magick/utility.c Sat Apr 08 14:19:11 2023 -0500 @@ -3714,6 +3714,221 @@ } /* + Convert a double to an int, with clipping. + Someday a warning or an error may be produced here. +*/ +MagickExport int MagickDoubleToInt(const double dval/*, ExceptionInfo *exception*/) +{ + int lval; + + do + { +#if defined(INFINITY) + if (dval == +INFINITY) + { + lval=INT_MAX; + break; + } + if (dval == -INFINITY) + { + lval=INT_MIN; + break; + } +#endif + if (isnan(dval)) + { + lval=0; + break; + } + if (floor(dval) > ((double) INT_MAX - 1)) + { + lval=INT_MAX; + break; + } + if (ceil(dval) < ((double) INT_MIN + 1)) + { + lval=INT_MIN; + break; + } + lval=(int) dval; + } while (0); + + return lval; +} + +/* + Convert a double to an unsigned long, with clipping. + Someday a warning or an error may be produced here. +*/ +MagickExport unsigned long MagickDoubleToULong(const double dval/*, ExceptionInfo *exception*/) +{ + unsigned long lval; + + do + { +#if defined(INFINITY) + if (dval == +INFINITY) + { + lval=ULONG_MAX; + break; + } + if (dval == -INFINITY) + { + lval=0; + break; + } +#endif + if (isnan(dval)) + { + lval=0; + break; + } + if (floor(dval) > ((double) ULONG_MAX - 1)) + { + lval=ULONG_MAX; + break; + } + if (ceil(dval) < 0.0) + { + lval=0; + break; + } + lval=(unsigned long) dval; + } while (0); + + return lval; +} + +/* + Convert a double to an unsigned int, with clipping. + Someday a warning or an error may be produced here. +*/ +MagickExport unsigned int MagickDoubleToUInt(const double dval/*, ExceptionInfo *exception*/) +{ + unsigned int lval; + + do + { +#if defined(INFINITY) + if (dval == +INFINITY) + { + lval=UINT_MAX; + break; + } + if (dval == -INFINITY) + { + lval=0; + break; + } +#endif + if (isnan(dval)) + { + lval=0; + break; + } + if (floor(dval) > ((double) UINT_MAX - 1)) + { + lval=UINT_MAX; + break; + } + if (ceil(dval) < 0.0) + { + lval=0; + break; + } + lval=(unsigned int) dval; + } while (0); + + return lval; +} + +/* + Convert a double to a short, with clipping. + Someday a warning or an error may be produced here. +*/ +MagickExport short int MagickDoubleToShort(const double dval/*, ExceptionInfo *exception*/) +{ + short int lval; + + do + { +#if defined(INFINITY) + if (dval == +INFINITY) + { + lval=SHRT_MAX; + break; + } + if (dval == -INFINITY) + { + lval=SHRT_MIN; + break; + } +#endif + if (isnan(dval)) + { + lval=0; + break; + } + if (floor(dval) > ((double) SHRT_MAX - 1)) + { + lval=SHRT_MAX; + break; + } + if (ceil(dval) < ((double) SHRT_MIN + 1)) + { + lval=SHRT_MIN; + break; + } + lval=(short int) dval; + } while (0); + + return lval; +} + +/* + Convert a double to an unsigned short, with clipping. + Someday a warning or an error may be produced here. +*/ +MagickExport unsigned short int MagickDoubleToUShort(const double dval/*, ExceptionInfo *exception*/) +{ + unsigned short int lval; + + do + { +#if defined(INFINITY) + if (dval == +INFINITY) + { + lval=USHRT_MAX; + break; + } + if (dval == -INFINITY) + { + lval=0; + break; + } +#endif + if (isnan(dval)) + { + lval=0; + break; + } + if (floor(dval) > ((double) USHRT_MAX - 1)) + { + lval=USHRT_MAX; + break; + } + if (ceil(dval) < 0.0) + { + lval=0; + break; + } + lval=(unsigned short int) dval; + } while (0); + + return lval; +} + +/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % diff -r 90a7c0b86df3 -r f462cca796b5 www/Changelog.html --- a/www/Changelog.html Sat Apr 08 12:14:35 2023 -0500 +++ b/www/Changelog.html Sat Apr 08 14:19:11 2023 -0500 @@ -40,9 +40,13 @@ <p>2023-04-08 Bob Friesenhahn <<a class="reference external" href="mailto:bfriesen%40simple.dallas.tx.us">bfriesen<span>@</span>simple<span>.</span>dallas<span>.</span>tx<span>.</span>us</a>></p> <blockquote> <ul class="simple"> +<li><p>coders/png.c (WriteOnePNGImage): Address undefined behavior +while converting floating point resolution to unsigned integer. +(SourceForge issue #706 test case 'bug19');</p></li> <li><p>magick/utility.c (GetGeometry): Improve geometry parser to validate that parsed double values do not underflow or overflow -when cast to 'unsigned long' or 'long' types.</p></li> +when cast to 'unsigned long' or 'long' types. (SourceForge issue +#706 test case 'bug11');</p></li> <li><p>coders/mpc.c (ReadMPCImage): If an attribute appears multiple times in the MPC header, only set it once.</p></li> <li><p>coders/miff.c (ReadMIFFImage): If an attribute appears multiple