[libpng16] Fixed GCC unsigned int->float warnings. Various versions of GCC

seem to generate warnings when an unsigned value is implicitly
converted to double. This is probably a GCC bug but this change
avoids the issue by explicitly converting to (int) where safe.
This commit is contained in:
John Bowler 2014-11-05 17:06:27 -06:00 committed by Glenn Randers-Pehrson
parent 5be76ae252
commit c9720568d0
2 changed files with 46 additions and 3 deletions

View File

@ -5053,6 +5053,10 @@ Version 1.6.15beta05 [November 5, 2014]
example.c, pngtest.c, and applications in the contrib directory. example.c, pngtest.c, and applications in the contrib directory.
Avoid out-of-bounds memory access in png_user_version_check(). Avoid out-of-bounds memory access in png_user_version_check().
Simplified and future-proofed png_user_version_check(). Simplified and future-proofed png_user_version_check().
Fixed GCC unsigned int->float warnings. Various versions of GCC
seem to generate warnings when an unsigned value is implicitly
converted to double. This is probably a GCC bug but this change
avoids the issue by explicitly converting to (int) where safe.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

45
png.c
View File

@ -3719,7 +3719,31 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
if (value > 0 && value < 255) if (value > 0 && value < 255)
{ {
# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
double r = floor(255*pow(value/255.,gamma_val*.00001)+.5); /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly
* convert this to a floating point value. This includes values that
* would overflow if 'value' were to be converted to 'int'.
*
* Apparently GCC, however, does an intermediate convertion to (int)
* on some (ARM) but not all (x86) platforms, possibly because of
* hardware FP limitations. (E.g. if the hardware convertion always
* assumes the integer register contains a signed value.) This results
* in ANSI-C undefined behavior for large values.
*
* Other implementations on the same machine might actually be ANSI-C90
* conformant and therefore compile spurious extra code for the large
* values.
*
* We can be reasonably sure that an unsigned to float convertion
* won't be faster than an int to float one. Therefore this code
* assumes responsibility for the undefined behavior, which it knows
* can't happen because of the check above.
*
* Note the argument to this routine is an (unsigned int) because, on
* 16-bit platforms, it is assigned a value which might be out of
* range for an (int); that would result in undefined behavior in the
* caller if the *argument* ('value') were to be declared (int).
*/
double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5);
return (png_byte)r; return (png_byte)r;
# else # else
png_int_32 lg2 = png_log8bit(value); png_int_32 lg2 = png_log8bit(value);
@ -3743,7 +3767,13 @@ png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
if (value > 0 && value < 65535) if (value > 0 && value < 65535)
{ {
# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5); /* The same (unsigned int)->(double) constraints apply here as above,
* however in this case the (unsigned int) to (int) convertion can
* overflow on an ANSI-C90 compliant system so the cast needs to ensure
* that this is not possible.
*/
double r = floor(65535*pow((png_int_32)value/65535.,
gamma_val*.00001)+.5);
return (png_uint_16)r; return (png_uint_16)r;
# else # else
png_int_32 lg2 = png_log16bit(value); png_int_32 lg2 = png_log16bit(value);
@ -3797,6 +3827,12 @@ png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,
{ {
/* Various values derived from 'shift': */ /* Various values derived from 'shift': */
PNG_CONST unsigned int num = 1U << (8U - shift); PNG_CONST unsigned int num = 1U << (8U - shift);
#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
/* CSE the division and work round wacky GCC warnings (see the comments
* in png_gamma_8bit_correct for where these come from.)
*/
PNG_CONST double fmax = 1./(((png_int_32)1 << (16U - shift))-1);
#endif
PNG_CONST unsigned int max = (1U << (16U - shift))-1U; PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);
unsigned int i; unsigned int i;
@ -3828,7 +3864,10 @@ png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,
png_uint_32 ig = (j << (8-shift)) + i; png_uint_32 ig = (j << (8-shift)) + i;
# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
/* Inline the 'max' scaling operation: */ /* Inline the 'max' scaling operation: */
double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5); /* See png_gamma_8bit_correct for why the cast to (int) is
* required here.
*/
double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5);
sub_table[j] = (png_uint_16)d; sub_table[j] = (png_uint_16)d;
# else # else
if (shift != 0) if (shift != 0)