File: autoconf.info, Node: Signed Overflow Advice, Next: Signed Integer Division, Prev: Optimization and Wraparound, Up: Integer Overflow
13.2.4 Practical Advice for Signed Overflow Issues
--------------------------------------------------
Ideally the safest approach is to avoid signed integer overflow
entirely. For example, instead of multiplying two signed integers, you
can convert them to double-width integers, multiply the wider values,
then test whether the result is in the narrower range. Or you can use
more-complicated code employing unsigned integers of the same width.
Rewriting code in this way will be inconvenient, though, especially
if the signed values might be negative and no wider type is available.
Using unsigned arithmetic to check for overflow is particularly painful
to do portably and efficiently when dealing with an integer type like
‘uid_t’ whose width and signedness vary from platform to platform.
Also, this approach may hurt performance.
Hence it is often useful to maintain code that needs wraparound on
overflow, instead of rewriting the code. The rest of this section
attempts to give practical advice for this situation.
To detect integer overflow portably when attempting operations like
‘sum = a + b’, you can use the C23 ‘’ macros ‘ckd_add’,
‘ckd_sub’, and ‘ckd_mul’. The following code adds two integers with
overflow wrapping around reliably in the sum:
#include
...
/* Set sum = a + b, with wraparound. */
if (ckd_add (&sum, a, b))
/* 'sum' has just the low order bits. */;
else
/* 'sum' is the correct answer. */;
To be portable to pre-C23 platforms you can use Gnulib's ‘stdckdint’
module, which emulates this part of C23 (*note Gnulib::). Invoking the
‘stdckdint’ macros typically costs just one machine instruction for the
arithmetic and another instruction for the rare branch on overflow.
If your code uses a signed loop index, make sure that the index
cannot overflow, along with all signed expressions derived from the
index. Here is a contrived example of problematic code with two
instances of overflow.
for (int i = INT_MAX - 10; i <= INT_MAX; i++)
if (i + 1 < 0)
{
report_overflow ();
break;
}
Because of the two overflows, a compiler might optimize away or
transform the two comparisons in a way that is incompatible with the
wraparound assumption.
If your code is intended to be compiled only by GCC and assumes
wraparound behavior, and you want to insulate it against any GCC
optimizations that would fail to support that behavior, you should use
GCC's ‘-fwrapv’ option, which causes signed overflow to wrap around
reliably (except for division and remainder, as discussed in the next
section).
If you need to write portable code and therefore cannot assume that
signed integer overflow wraps around reliably, you should consider
debugging with a GCC option that causes signed overflow to raise an
exception. These options include ‘-fsanitize=undefined’ and ‘-ftrapv’.