https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79479

--- Comment #9 from Paul Eggert <eggert at gnu dot org> ---
> 1) It's too subtle for non-expert programmers to understand.

Actually, it's typically easy for non-experts to follow this. For example,
although GCC falsely warns about this:

  /*1*/ if (0) return INT_MAX + 1; else return 0;

GCC handles this correctly:

  /*2*/ return 0 ? INT_MAX + 1 : 0;

If /*1*/ were really "too subtle" for non-experts, /*2*/ would also be "too
subtle". In practice, though, /*2*/ is working well and is not "too subtle",
and GCC should be able to make /*1*/ work as well.

> 2) It's unclear under what conditions the warning should or should not be
> issued.

As a first approximation, have GCC treat /*1*/ like it treats /*2*/.

> What if the controlling expression evaluates to zero but is not a
> constant expression?

Do what /*2*/ does.

> With or without optimization?

Again, do what /*2*/ does.

> 3) Avoiding the warning would require removing the implementation from the
> front end and adding it to the middle-end, which tends to lead to
> inconsistencies and both false positives and negatives.  (This isn't an
> argument against also handling the overflow in the middle-end, as
> -Wstrict-overflow does, but rather one against removing it from the front 
> end.)

Perhaps, given GCC's current internal structure it's nontrivial to fix GCC to
eliminate the false alarms.  However, this doesn't affect the fact that they
are false alarms, and that problems in this area are due to problems in GCC's
internal structure rather than being problems intrinsic to the analysis of C
programs.

> 4) There are a number of similar warnings that behave the same way (e.g.,
> -Wshift-negative-value, -Wshift-count-overflow and -Wshift-overflow).  GCC
> should be consistent in handling all these and so all the others would need to
> change as well.

Yes, that sounds right.

> 5) There is an easy way to rewrite the code to avoid the warning:
>
>   int too_large (long x)
>   {
>   #if INT_MAX < LONG_MAX   // or in GCC 7, INT_SIZE < LONG_SIZE
>     return 32768 * 65536L < x;
>   #else
>     return 0;
>   #endif
>   }

Although #if works for this particular example, it does not work with modern
programming styles that try to avoid the preprocessor for various good reasons.
Worse, #if does not work for expressions that contain constants that are not
visible to the C proprocessor. In the following example, GCC reports a false
alarm and this cannot be handled by the preprocessor because the preprocessor
cannot see the values of ELTS and MULTIPLIER. Another example: sizeof is
commonly involved in overflow checks, and the preprocessor cannot handle
sizeof.

#include <limits.h>
/* Assume these are supplied by some header elsewhere, as enums.  */
enum { ELTS = 1000000000, MULTIPLIER = 10 };
/* Return ELTS times MULTIPLIER.  If the result would overflow,
   return the closest representable value.  */
int ELTS_times_MULTIPLIER_saturated (void) {
  enum { a = ELTS, b = MULTIPLIER };
  if (b < 0) {
    if (a < 0) {
      if (INT_MAX / b <= a)
        return INT_MAX;
    } else {
      if (b != -1 && INT_MIN / b < a)
        return INT_MIN;
    }
  } else if (b != 0) {
    if (a < 0) {
      if (a < INT_MIN / b)
        return INT_MIN;
    } else {
      if (INT_MAX / b < a)
        return INT_MAX;
    }
  }
  return a * b;
}

Reply via email to