Some time ago (a year?) I was told on this mailing-list that code
breakage due to undefinedness of signed overflow is not too common (I at
least claimed with no evidence that it was more than one bug per 1,000
lines). My claim was counterclaimed by something like "most of the time
people work with small enough values, so overflows don't happen too many
times in practice".
This claim is a non sequitur.
What I would say is, people *don't understand why a compiler needs to
assume undefined overflow semantics*, because people work with small
values and don't care about the boundary conditions.
For example, most programmers that know assembly language will
appreciate if the compiler can use the processor's support for loop with
a known number of iterations (mtctr on PPC, for example). However, I'm
pretty sure that, if you present these two pieces of code to some good
programmers,
unsigned int i;
for (i = 0; i <= n; i++)
...
unsigned int i;
for (i = 0; i < n; i++)
...
where the compiler uses mtctr only in the second case, most of them will
think that the compiler has bug. Almost nobody will realize that the
first can loop infinitely, and the second cannot (which is the reason
why the compiler cannot optimize them in the same way).
Well, these programmers *are* assuming undefined overflow semantics even
on unsigned types. Maybe they would like overflow semantics should be
defined in some cases and undefined in others? Fine by me, that would
be -fwrapv -funsafe-loop-optimizations in GCC; but a language standard
cannot go to such detail!
On the autoconf mailing list, Paul Eggert mentioned as a good compromise
that GCC could treat signed overflow as undefined only for loops and not
in general. Except that the original gnulib bug report was in a loop,
so this compromise would leave that case undefined.
You may think that the analogy is far fetched? In that case, I'll pick
some gcc source file, at random and look for signed operations in it:
categorize_ctor_elements_1(......) in gcc/expr.c:
_elts += mult * nz;
elt_count += mult * ic;
Both assume that neither the multiplication, nor the addition overflow.
I see this as a *counterexample*: it shows that programmers don't care
about having wrapping overflow, in fact they don't care about overflow
at all. This code is incorrect not only if overflow is undefined, but
also if overflow wraps (-fwrapv); it is correct if overflow aborts
(-ftrapv).
Paolo