Eli Zaretskii wrote:
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=37006
Thanks for reporting that bug. I fixed it by installing the attached into
Gnulib. While working on the fix I discovered and reported a bug in GCC's
integer-overflow builtins: see:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91450
The new Gnulib code works around this GCC bug.
As you can see by inspecting the patch, it can be surprisingly difficult to do
integer overflow checking correctly for all edge cases, particularly given the
compiler bugs in this area. For example, the Gnulib code simply ignores Clang's
integer-overflow builtins, because working around Clang's builtins' bugs is more
trouble than it's worth.
Ad-hoc integer-overflow checking is unfortunately quite error-prone in C-like
languages, which why INT_ADD_WRAPV etc. are useful.
>From 8a7ac1d24ac54ca8f076320a61548c343040357b Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 14 Aug 2019 17:43:46 -0700
Subject: [PATCH] intprops: support unsigned *_WRAPV results
Add support for unsigned, unsigned long, and unsigned long long
results to INT_ADD_WRAPV, INT_SUBTRACT_WRAPV, and
INT_MULTIPLY_WRAPV. Also, work around GCC bug 91450, and fix a
bug with unsigned inputs reported by Eli Zaretskii in:
https://lists.gnu.org/r/bug-gnulib/2019-08/msg00012.html
* config/srclist.txt: Break the glibc connection for intprops.h
temporarily, while more testing is done in Gnulib-using apps.
* lib/intprops.h (INT_ADD_WRAPV, INT_SUBTRACT_WRAPV)
(INT_MULTIPLY_WRAPV, _GL_INT_OP_WRAPV, _GL_INT_OP_WRAPV_LONGISH):
Support unsigned results no narrower than unsigned int. Report
overflow correctly if some arguments are unsigned.
(_GL_BUILTIN_MUL_OVERFLOW): New macro, to work around GCC bug 91450.
(_GL_INT_OP_CALC): Simplify now that the OVERFLOW argument does
the right thing with narrow args.
(_GL_INT_OP_CALC1): Remove. All callers removed.
(_GL_INT_ADD_RANGE_OVERFLOW, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
(_GL_INT_MULTIPLY_RANGE_OVERFLOW): New macros.
* tests/test-intprops.c: Check for bugs and test new behavior.
---
ChangeLog | 22 ++++++
config/srclist.txt | 3 +-
lib/intprops.h | 154 ++++++++++++++++++++++++++++++++++--------
tests/test-intprops.c | 78 +++++++++++++++------
4 files changed, 209 insertions(+), 48 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4d1eeddfc..7fe978f4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2019-08-14 Paul Eggert <[email protected]>
+
+ intprops: support unsigned *_WRAPV results
+ Add support for unsigned, unsigned long, and unsigned long long
+ results to INT_ADD_WRAPV, INT_SUBTRACT_WRAPV, and
+ INT_MULTIPLY_WRAPV. Also, work around GCC bug 91450, and fix a
+ bug with unsigned inputs reported by Eli Zaretskii in:
+ https://lists.gnu.org/r/bug-gnulib/2019-08/msg00012.html
+ * config/srclist.txt: Break the glibc connection for intprops.h
+ temporarily, while more testing is done in Gnulib-using apps.
+ * lib/intprops.h (INT_ADD_WRAPV, INT_SUBTRACT_WRAPV)
+ (INT_MULTIPLY_WRAPV, _GL_INT_OP_WRAPV, _GL_INT_OP_WRAPV_LONGISH):
+ Support unsigned results no narrower than unsigned int. Report
+ overflow correctly if some arguments are unsigned.
+ (_GL_BUILTIN_MUL_OVERFLOW): New macro, to work around GCC bug 91450.
+ (_GL_INT_OP_CALC): Simplify now that the OVERFLOW argument does
+ the right thing with narrow args.
+ (_GL_INT_OP_CALC1): Remove. All callers removed.
+ (_GL_INT_ADD_RANGE_OVERFLOW, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
+ (_GL_INT_MULTIPLY_RANGE_OVERFLOW): New macros.
+ * tests/test-intprops.c: Check for bugs and test new behavior.
+
2019-08-14 Bruno Haible <[email protected]>
get_progname_of: New module.
diff --git a/config/srclist.txt b/config/srclist.txt
index b86e6a57a..bb6ad87ab 100644
--- a/config/srclist.txt
+++ b/config/srclist.txt
@@ -46,7 +46,8 @@ $GNUORG Copyright/request-assign.future doc/Copyright
$GNUORG Copyright/request-assign.program doc/Copyright
$GNUORG Copyright/request-disclaim.changes doc/Copyright
-$LIBCSRC include/intprops.h lib
+# Temporarily newer in Gnulib than in glibc.
+#$LIBCSRC include/intprops.h lib
$LIBCSRC posix/regcomp.c lib
$LIBCSRC posix/regex.c lib
$LIBCSRC posix/regex.h lib
diff --git a/lib/intprops.h b/lib/intprops.h
index 140f6d2a4..556cadec8 100644
--- a/lib/intprops.h
+++ b/lib/intprops.h
@@ -111,8 +111,8 @@
Subtract 1 for the sign bit if T is signed, and then add 1 more for
a minus sign if needed.
- Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is
- signed, this macro may overestimate the true bound by one byte when
+ Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 1 when its argument is
+ unsigned, this macro may overestimate the true bound by one byte when
applied to unsigned types of size 2, 4, 16, ... bytes. */
#define INT_STRLEN_BOUND(t) \
(INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \
@@ -281,7 +281,9 @@
The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators
might not yield numerically correct answers due to arithmetic overflow.
- The INT_<op>_WRAPV macros also store the low-order bits of the answer.
+ The INT_<op>_WRAPV macros compute the low-order bits of the sum,
+ difference, and product of two C integers, and return 1 if these
+ low-order bits are not numerically correct.
These macros work correctly on all known practical hosts, and do not rely
on undefined behavior due to signed arithmetic overflow.
@@ -309,9 +311,12 @@
arguments should not have side effects.
The WRAPV macros are not constant expressions. They support only
- +, binary -, and *. The result type must be signed.
+ +, binary -, and *. The result type must be either signed, or an
+ unsigned type that is 'unsigned int' or wider. Because the WRAPV
+ macros convert the result, the report overflow in different
+ circumstances than the OVERFLOW macros do.
- These macros are tuned for their last argument being a constant.
+ These macros are tuned for their last input argument being a constant.
Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
A % B, and A << B would overflow, respectively. */
@@ -348,11 +353,21 @@
/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
Return 1 if the result overflows. See above for restrictions. */
#define INT_ADD_WRAPV(a, b, r) \
- _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW)
+ _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, \
+ _GL_INT_ADD_RANGE_OVERFLOW)
#define INT_SUBTRACT_WRAPV(a, b, r) \
- _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW)
+ _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, \
+ _GL_INT_SUBTRACT_RANGE_OVERFLOW)
#define INT_MULTIPLY_WRAPV(a, b, r) \
- _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW)
+ _GL_INT_OP_WRAPV (a, b, r, *, _GL_BUILTIN_MUL_OVERFLOW, \
+ _GL_INT_MULTIPLY_RANGE_OVERFLOW)
+
+/* Like __builtin_mul_overflow, but work around GCC bug 91450. */
+#define _GL_BUILTIN_MUL_OVERFLOW(a, b, r) \
+ ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \
+ && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
+ ? (__builtin_mul_overflow (a, b, r), 1) \
+ : __builtin_mul_overflow (a, b, r))
/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
@@ -379,41 +394,79 @@
signed char: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
signed char, SCHAR_MIN, SCHAR_MAX), \
+ unsigned char: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ unsigned char, 0, UCHAR_MAX), \
short int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
short int, SHRT_MIN, SHRT_MAX), \
+ unsigned short int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ unsigned short int, 0, USHRT_MAX), \
int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
int, INT_MIN, INT_MAX), \
+ unsigned int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ unsigned int, 0, UINT_MAX), \
long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX), \
+ unsigned long int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ unsigned long int, 0, ULONG_MAX), \
long long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
- long long int, LLONG_MIN, LLONG_MAX)))
+ long long int, LLONG_MIN, LLONG_MAX),
+ unsigned long long int: \
+ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ unsigned long long int, ULLONG_MIN, ULLONG_MAX)))
#else
+/* This fallback implementation uses _GL_SIGNED_TYPE_OR_EXPR, and so
+ may guess wrong on some non-GNU pre-C11 compilers when the type of
+ *R is unsigned char or unsigned short. This is why the
+ documentation for INT_ADD_WRAPV says that the result type, if
+ unsigned, should be unsigned int or wider. */
# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \
(sizeof *(r) == sizeof (signed char) \
- ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
- signed char, SCHAR_MIN, SCHAR_MAX) \
+ ? (_GL_SIGNED_TYPE_OR_EXPR (*(r)) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ signed char, SCHAR_MIN, SCHAR_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ unsigned char, 0, UCHAR_MAX)) \
: sizeof *(r) == sizeof (short int) \
- ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
- short int, SHRT_MIN, SHRT_MAX) \
+ ? (_GL_SIGNED_TYPE_OR_EXPR (*(r)) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ short int, SHRT_MIN, SHRT_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ unsigned short int, 0, USHRT_MAX)) \
: sizeof *(r) == sizeof (int) \
- ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
- int, INT_MIN, INT_MAX) \
+ ? (EXPR_SIGNED (*(r)) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ int, INT_MIN, INT_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
+ unsigned int, 0, UINT_MAX)) \
: _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
# ifdef LLONG_MAX
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
(sizeof *(r) == sizeof (long int) \
- ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
- long int, LONG_MIN, LONG_MAX) \
- : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
- long long int, LLONG_MIN, LLONG_MAX))
+ ? (EXPR_SIGNED (*(r)) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ unsigned long int, 0, ULONG_MAX)) \
+ : (EXPR_SIGNED (*(r)) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ long long int, LLONG_MIN, LLONG_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
+ unsigned long long int, 0, ULLONG_MAX)))
# else
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
- _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
- long int, LONG_MIN, LONG_MAX)
+ (EXPR_SIGNED (*(r)) \
+ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ long int, LONG_MIN, LONG_MAX) \
+ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
+ unsigned long int, 0, ULONG_MAX))
# endif
#endif
@@ -422,13 +475,7 @@
overflow problems. *R's type is T, with extrema TMIN and TMAX.
T must be a signed integer type. Return 1 if the result overflows. */
#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
- (sizeof ((a) op (b)) < sizeof (t) \
- ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \
- : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax))
-#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \
- ((overflow (a, b) \
- || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \
- || (tmax) < ((a) op (b))) \
+ (overflow (a, b, tmin, tmax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
@@ -452,4 +499,55 @@
#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
((t) ((ut) (a) op (ut) (b)))
+/* Return true if the numeric values A + B, A - B, A * B fall outside
+ the range TMIN..TMAX. Arguments should be integer expressions
+ without side effects. TMIN should be signed and nonpositive.
+ TMAX should be positive, and should be signed unless TMIN is zero. */
+#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
+ ((b) < 0 \
+ ? (((tmin) \
+ ? ((EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \
+ && (a) < (tmin) - (b)) \
+ : (a) <= -1 - (b)) \
+ || ((EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \
+ : (a) < 0 \
+ ? (((tmin) \
+ ? ((EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \
+ && (b) < (tmin) - (a)) \
+ : (b) <= -1 - (a)) \
+ || ((EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \
+ && (tmax) < (a) + (b))) \
+ : (tmax) < (b) || (tmax) - (b) < (a))
+#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \
+ (((a) < 0) == ((b) < 0) \
+ ? ((a) < (b) \
+ ? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \
+ : (tmax) < (a) - (b)) \
+ : (a) < 0 \
+ ? ((!EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \
+ || (a) - (tmin) < (b)) \
+ : ((! (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
+ && EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \
+ && (tmax) <= -1 - (b)) \
+ || (tmax) + (b) < (a)))
+#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \
+ ((b) < 0 \
+ ? ((a) < 0 \
+ ? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
+ ? (a) < (tmax) / (b) \
+ : ((INT_NEGATE_OVERFLOW (b) \
+ ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (b) - 1) \
+ : (tmax) / -(b)) \
+ <= -1 - (a))) \
+ : INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
+ ? (EXPR_SIGNED (a) ? 0 < (a) + (tmin) : (a) && -1 - (tmin) < (a) - 1) \
+ : (tmin) / (b) < (a)) \
+ : (b) == 0 \
+ ? 0 \
+ : ((a) < 0 \
+ ? (INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \
+ ? (EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \
+ : (tmin) / (a) < (b)) \
+ : (tmax) / (b) < (a)))
+
#endif /* _GL_INTPROPS_H */
diff --git a/tests/test-intprops.c b/tests/test-intprops.c
index babcafd60..be0c6b3a7 100644
--- a/tests/test-intprops.c
+++ b/tests/test-intprops.c
@@ -56,6 +56,9 @@
#define DONTCARE __LINE__
+int int_minus_2 = -2;
+int int_1 = 1;
+
int
main (void)
{
@@ -237,33 +240,48 @@ main (void)
/* INT_<op>_OVERFLOW and INT_<op>_WRAPV with mixed types. */
#define CHECK_SUM(a, b, t, v, vres) \
- CHECK_SUM1(a, b, t, v, vres); \
- CHECK_SUM1(b, a, t, v, vres)
- #define CHECK_SSUM(a, b, t, v, vres) \
- CHECK_SSUM1(a, b, t, v, vres); \
- CHECK_SSUM1(b, a, t, v, vres)
+ CHECK_SUM1 (a, b, t, v, vres); \
+ CHECK_SUM1 (b, a, t, v, vres)
+ #define CHECK_SUM_WRAPV(a, b, t, v, vres, okres) \
+ CHECK_SUM_WRAPV1 (a, b, t, v, vres, okres); \
+ CHECK_SUM_WRAPV1 (b, a, t, v, vres, okres)
#define CHECK_SUM1(a, b, t, v, vres) \
- VERIFY (INT_ADD_OVERFLOW (a, b) == (v))
- #define CHECK_SSUM1(a, b, t, v, vres) \
- CHECK_SUM1(a, b, t, v, vres); \
+ VERIFY (INT_ADD_OVERFLOW (a, b) == (v)); \
+ CHECK_SUM_WRAPV1 (a, b, t, v, vres, (a) + (b))
+ #define CHECK_SUM_WRAPV1(a, b, t, v, vres, okres) \
{ \
t result; \
ASSERT (INT_ADD_WRAPV (a, b, &result) == (v)); \
- ASSERT (result == ((v) ? (vres) : ((a) + (b)))); \
+ ASSERT (result == ((v) ? (vres) : (okres))); \
}
- CHECK_SSUM (-1, LONG_MIN, long int, true, LONG_MAX);
+ CHECK_SUM (-1, LONG_MIN, long int, true, LONG_MAX);
CHECK_SUM (-1, UINT_MAX, unsigned int, false, DONTCARE);
- CHECK_SSUM (-1L, INT_MIN, long int, INT_MIN == LONG_MIN,
+ CHECK_SUM (-1L, INT_MIN, long int, INT_MIN == LONG_MIN,
INT_MIN == LONG_MIN ? INT_MAX : DONTCARE);
CHECK_SUM (0u, -1, unsigned int, true, 0u + -1);
CHECK_SUM (0u, 0, unsigned int, false, DONTCARE);
CHECK_SUM (0u, 1, unsigned int, false, DONTCARE);
- CHECK_SSUM (1, LONG_MAX, long int, true, LONG_MIN);
+ CHECK_SUM (1, LONG_MAX, long int, true, LONG_MIN);
CHECK_SUM (1, UINT_MAX, unsigned int, true, 0u);
- CHECK_SSUM (1L, INT_MAX, long int, INT_MAX == LONG_MAX,
+ CHECK_SUM (1L, INT_MAX, long int, INT_MAX == LONG_MAX,
INT_MAX == LONG_MAX ? INT_MIN : DONTCARE);
CHECK_SUM (1u, INT_MAX, unsigned int, INT_MAX == UINT_MAX, 1u + INT_MAX);
CHECK_SUM (1u, INT_MIN, unsigned int, true, 1u + INT_MIN);
+ CHECK_SUM_WRAPV (-1, 1u, int, false, DONTCARE, 0);
+ CHECK_SUM_WRAPV (-1, 1ul, int, false, DONTCARE, 0);
+ CHECK_SUM_WRAPV (-1l, 1u, int, false, DONTCARE, 0);
+ CHECK_SUM_WRAPV (-100, 1000u, int, false, DONTCARE, 900);
+ CHECK_SUM_WRAPV (INT_MIN, UINT_MAX, int, false, DONTCARE, INT_MAX);
+ CHECK_SUM_WRAPV (1u, INT_MAX, int, true, INT_MIN, DONTCARE);
+ CHECK_SUM_WRAPV (INT_MAX, 1, long int, LONG_MAX <= INT_MAX, INT_MIN,
+ INT_MAX + 1L);
+ CHECK_SUM_WRAPV (UINT_MAX, 1, long int, LONG_MAX <= UINT_MAX, 0,
+ UINT_MAX + 1L);
+ CHECK_SUM_WRAPV (INT_MAX, 1, unsigned long int, ULONG_MAX <= INT_MAX, 0,
+ INT_MAX + 1uL);
+ CHECK_SUM_WRAPV (UINT_MAX, 1, unsigned long int, ULONG_MAX <= UINT_MAX, 0,
+ UINT_MAX + 1uL);
+
{
long int result;
ASSERT (INT_ADD_WRAPV (1, INT_MAX, &result) == (INT_MAX == LONG_MAX));
@@ -273,7 +291,9 @@ main (void)
#define CHECK_DIFFERENCE(a, b, t, v, vres) \
VERIFY (INT_SUBTRACT_OVERFLOW (a, b) == (v))
#define CHECK_SDIFFERENCE(a, b, t, v, vres) \
- CHECK_DIFFERENCE(a, b, t, v, vres); \
+ CHECK_DIFFERENCE (a, b, t, v, vres); \
+ CHECK_SDIFFERENCE_WRAPV (a, b, t, v, vres)
+ #define CHECK_SDIFFERENCE_WRAPV(a, b, t, v, vres) \
{ \
t result; \
ASSERT (INT_SUBTRACT_WRAPV (a, b, &result) == (v)); \
@@ -290,6 +310,11 @@ main (void)
CHECK_SDIFFERENCE (-1, INT_MAX, int, false, -1 - INT_MAX);
CHECK_SDIFFERENCE (0, INT_MIN, int, INT_MIN < -INT_MAX, INT_MIN);
CHECK_SDIFFERENCE (0, INT_MAX, int, false, 0 - INT_MAX);
+ CHECK_SDIFFERENCE_WRAPV (-1, 1u, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (-1, 1ul, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (-1l, 1u, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (0u, INT_MAX, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (1u, INT_MIN, int, true, 1u - INT_MIN);
{
long int result;
ASSERT (INT_SUBTRACT_WRAPV (INT_MAX, -1, &result) == (INT_MAX == LONG_MAX));
@@ -297,15 +322,20 @@ main (void)
}
#define CHECK_PRODUCT(a, b, t, v, vres) \
- CHECK_PRODUCT1(a, b, t, v, vres); \
- CHECK_PRODUCT1(b, a, t, v, vres)
+ CHECK_PRODUCT1 (a, b, t, v, vres); \
+ CHECK_PRODUCT1 (b, a, t, v, vres)
#define CHECK_SPRODUCT(a, b, t, v, vres) \
- CHECK_SPRODUCT1(a, b, t, v, vres); \
- CHECK_SPRODUCT1(b, a, t, v, vres)
+ CHECK_SPRODUCT1 (a, b, t, v, vres); \
+ CHECK_SPRODUCT1 (b, a, t, v, vres)
+ #define CHECK_SPRODUCT_WRAPV(a, b, t, v, vres) \
+ CHECK_SPRODUCT_WRAPV1 (a, b, t, v, vres); \
+ CHECK_SPRODUCT_WRAPV1 (b, a, t, v, vres)
#define CHECK_PRODUCT1(a, b, t, v, vres) \
VERIFY (INT_MULTIPLY_OVERFLOW (a, b) == (v))
#define CHECK_SPRODUCT1(a, b, t, v, vres) \
- CHECK_PRODUCT1(a, b, t, v, vres); \
+ CHECK_PRODUCT1 (a, b, t, v, vres); \
+ CHECK_SPRODUCT_WRAPV1 (a, b, t, v, vres)
+ #define CHECK_SPRODUCT_WRAPV1(a, b, t, v, vres) \
{ \
t result; \
ASSERT (INT_MULTIPLY_WRAPV (a, b, &result) == (v)); \
@@ -343,6 +373,10 @@ main (void)
CHECK_PRODUCT (INT_MIN, UINT_MAX, unsigned int, true, INT_MIN * UINT_MAX);
CHECK_PRODUCT (INT_MIN, ULONG_MAX, unsigned long int, true,
INT_MIN * ULONG_MAX);
+ CHECK_SPRODUCT_WRAPV (-1, INT_MAX + 1u, int, false, DONTCARE);
+ CHECK_SPRODUCT_WRAPV (-1, 1u, int, false, DONTCARE);
+ CHECK_SPRODUCT (0, ULONG_MAX, int, false, DONTCARE);
+ CHECK_SPRODUCT (0u, LONG_MIN, int, false, DONTCARE);
{
long int result;
ASSERT (INT_MULTIPLY_WRAPV (INT_MAX, INT_MAX, &result)
@@ -365,6 +399,12 @@ main (void)
}
# endif
+ /* Check for GCC bug 91450. */
+ {
+ unsigned long long result;
+ ASSERT (INT_MULTIPLY_WRAPV (int_minus_2, int_1, &result) && result == -2);
+ }
+
#define CHECK_QUOTIENT(a, b, v) VERIFY (INT_DIVIDE_OVERFLOW (a, b) == (v))
CHECK_QUOTIENT (INT_MIN, -1L, INT_MIN == LONG_MIN);
--
2.17.1