]> Savannah Git Hosting - gnulib.git/commitdiff
intprops: Add INT_ADD_OK etc.
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 5 Dec 2020 23:54:22 +0000 (15:54 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 6 Dec 2020 01:35:34 +0000 (17:35 -0800)
* doc/intprops.texi (Checking Integer Overflow): New section.
* lib/intprops.h: From a suggestion by Bruno Haible in:
https://lists.gnu.org/r/bug-gnulib/2020-12/msg00051.html
(SAFE_INT_ADD, SAFE_INT_SUBTRACT, SAFE_INT_MULTIPLY): New macros.

ChangeLog
doc/intprops.texi
lib/intprops.h

index 8db9975f55f7f2d9cf0b6dde096887cc6c46e216..72895ac78d16bda763968f5dfaacc6ce13a78ed7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2020-12-05  Paul Eggert  <eggert@cs.ucla.edu>
 
+       intprops: Add INT_ADD_OK etc.
+       * doc/intprops.texi (Checking Integer Overflow): New section.
+       * lib/intprops.h: From a suggestion by Bruno Haible in:
+       https://lists.gnu.org/r/bug-gnulib/2020-12/msg00051.html
+       (SAFE_INT_ADD, SAFE_INT_SUBTRACT, SAFE_INT_MULTIPLY): New macros.
+
        doc: move exotic platfroms to Target Platforms
        * doc/gnulib-intro.texi (Supported Platforms)
        (Formerly Supported Platforms, Unsupported Platforms):
index 294c235f5fe43efd4296c198c1394e25e935ad39..f3a958a75f2de49b371683b93a4fee1344a0304a 100644 (file)
@@ -49,7 +49,8 @@ but it does not assume that signed integer arithmetic wraps around.
 @menu
 * Arithmetic Type Properties::  Determining properties of arithmetic types.
 * Integer Bounds::              Bounds on integer values and representations.
-* Wraparound Arithmetic::       Well-defined behavior on signed overflow.
+* Checking Integer Overflow::   Checking for overflow while computing integers.
+* Wraparound Arithmetic::       Well-defined behavior on integer overflow.
 * Integer Type Overflow::       General integer overflow checking.
 * Integer Range Overflow::      Integer overflow checking if bounds are known.
 @end menu
@@ -150,6 +151,107 @@ in_off_t_range (intmax_t a)
 @}
 @end example
 
+@node Checking Integer Overflow
+@subsection Checking Integer Overflow
+
+@cindex integer overflow checking
+
+Signed integer arithmetic has undefined behavior on overflow in C@.
+Although almost all modern computers use two's complement signed
+arithmetic that is well-defined to wrap around, C compilers routinely
+optimize assuming that signed integer overflow cannot occur, which
+means that a C program cannot easily get at the underlying machine
+arithmetic.  For example:
+
+@example
+if ((a + b < b) == (a < 0))
+  a += b;
+else
+  print ("overflow");
+@end example
+
+@noindent
+might not work as expected if @code{a} and @code{b} are signed,
+because a compiler can assume that signed overflow cannot occur and
+treat the entire @code{if} expression as if it were true.  And even if
+@code{a} is unsigned, the expression might not work as expected if
+@code{b} is negative or is wider than @code{a}.
+
+The following macros work around this problem by returning an overflow
+indication while computing the sum, difference, or product of two
+integers.  For example, if @code{i} is of type @code{int},
+@code{INT_ADD_OK (INT_MAX - 1, 1, &i)} sets @code{i} to
+@code{INT_MAX} and returns true, whereas @code{INT_ADD_OK (INT_MAX, 1,
+&i)} returns false.
+
+Example usage:
+
+@example
+#include <intprops.h>
+#include <stdio.h>
+
+/* Compute A * B, reporting whether overflow occurred.  */
+void
+print_product (long int a, long int b)
+@{
+  long int r;
+  if (INT_MULTIPLY_OK (a, b, r))
+    printf ("result is %ld\n", r);
+  else
+    printf ("overflow\n");
+@}
+@end example
+
+These macros work for both signed and unsigned integers, so they can
+be used with integer types like @code{time_t} that may or may not be
+signed, depending on the platform.
+
+These macros have the following restrictions:
+
+@itemize @bullet
+@item
+Their first two arguments must be integer expressions.
+
+@item
+Their last argument must be a non-null pointer to an integer.
+
+@item
+They may evaluate their arguments zero or multiple times, so the
+arguments should not have side effects.
+
+@item
+They are not necessarily constant expressions, even if all their
+arguments are constant expressions.
+@end itemize
+
+@table @code
+@item INT_ADD_OK (@var{a}, @var{b}, @var{r})
+@findex INT_ADD_OK
+Compute the sum of @var{a} and @var{b}.  If it fits into
+@code{*@var{r}}, store it there and return true.  Otherwise return
+false, possibly modifying @code{*@var{r}} to an unspecified value.
+See above for restrictions.
+
+@item INT_SUBTRACT_OK (@var{a}, @var{b}, @var{r})
+@findex INT_SUBTRACT_OK
+Compute the difference between @var{a} and @var{b}.  If it fits into
+@code{*@var{r}}, store it there and return true.  Otherwise return
+false, possibly modifying @code{*@var{r}} to an unspecified value.
+See above for restrictions.
+
+@item INT_MULTIPLY_OK (@var{a}, @var{b}, @var{r})
+@findex INT_MULTIPLY_OK
+Compute the product of @var{a} and @var{b}.  If it fits into
+@code{*@var{r}}, store it there and return true.  Otherwise return
+false, possibly modifying @code{*@var{r}} to an unspecified value.
+See above for restrictions.
+@end table
+
+Other macros are available if you need wrapped-around results when
+overflow occurs (@pxref{Wraparound Arithmetic}), or if you need to
+check for overflow in operations other than addition, subtraction, and
+multiplication (@pxref{Integer Type Overflow}).
+
 @node Wraparound Arithmetic
 @subsection Wraparound Arithmetic with Integers
 
@@ -238,6 +340,11 @@ low-order bits are the mathematically-correct product.  See above for
 restrictions.
 @end table
 
+Other macros are available if you do not need wrapped-around results
+when overflow occurs (@pxref{Checking Integer Overflow}), or if you
+need to check for overflow in operations other than addition,
+subtraction, and multiplication (@pxref{Integer Type Overflow}).
+
 @node Integer Type Overflow
 @subsection Integer Type Overflow
 
index cb086715bcb418ff4043e3822f6c6a86720063d6..8cc8138f90c203a7b3905465cb45824ebcfb7158 100644 (file)
          : (tmin) / (a) < (b)) \
       : (tmax) / (b) < (a)))
 
+/* The following macros compute A + B, A - B, and A * B, respectively.
+   If no overflow occurs, they set *R to the result and return 1;
+   otherwise, they return 0 and may modify *R.
+
+   Example usage:
+
+     long int result;
+     if (INT_ADD_OK (a, b, &result))
+       printf ("result is %ld\n", result);
+     else
+       printf ("overflow\n");
+
+   A, B, and *R should be integers; they need not be the same type,
+   and they need not be all signed or all unsigned.
+
+   These macros work correctly on all known practical hosts, and do not rely
+   on undefined behavior due to signed arithmetic overflow.
+
+   These macros are not constant expressions.
+
+   These macros may evaluate their arguments zero or multiple times, so the
+   arguments should not have side effects.
+
+   These macros are tuned for B being a constant.  */
+
+#define INT_ADD_OK(a, b, r) ! INT_ADD_WRAPV (a, b, r)
+#define INT_SUBTRACT_OK(a, b, r) ! INT_SUBTRACT_WRAPV (a, b, r)
+#define INT_MULTIPLY_OK(a, b, r) ! INT_MULTIPLY_WRAPV (a, b, r)
+
 #endif /* _GL_INTPROPS_H */