summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Bowler <jbowler@acm.org>2014-11-05 17:06:27 -0600
committerGlenn Randers-Pehrson <glennrp at users.sourceforge.net>2014-11-05 17:06:27 -0600
commitc9720568d0f69c87f5647bd77253a4bdfab912c7 (patch)
treec46d9176a2b7bbb41e2e5891b54b5939061b313a
parent5be76ae2525b00c51aaa122cb9c4121ab0005496 (diff)
downloadlibpng-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--CHANGES4
-rw-r--r--png.c45
2 files changed, 46 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 9e7c2c5f6..46a497455 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/png.c b/png.c
index 4cf592334..f4d622123 100644
--- a/png.c
+++ b/png.c
@@ -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)