diff options
author | John Bowler <jbowler@acm.org> | 2014-11-05 17:06:27 -0600 |
---|---|---|
committer | Glenn Randers-Pehrson <glennrp at users.sourceforge.net> | 2014-11-05 17:06:27 -0600 |
commit | c9720568d0f69c87f5647bd77253a4bdfab912c7 (patch) | |
tree | c46d9176a2b7bbb41e2e5891b54b5939061b313a | |
parent | 5be76ae2525b00c51aaa122cb9c4121ab0005496 (diff) | |
download | libpng-c9720568d0f69c87f5647bd77253a4bdfab912c7.tar.gz |
[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.
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | png.c | 45 |
2 files changed, 46 insertions, 3 deletions
@@ -5053,6 +5053,10 @@ Version 1.6.15beta05 [November 5, 2014] example.c, pngtest.c, and applications in the contrib directory. Avoid out-of-bounds memory access in 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 (subscription required; visit @@ -3719,7 +3719,31 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) if (value > 0 && value < 255) { # 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; # else 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) { # 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; # else 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': */ 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_by_2 = 1U << (15U-shift); 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; # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* 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; # else if (shift != 0) |