On Debian x86_64, I get the following failure with gcc (Debian 20180908-1) 9.0.0 20180908 (experimental) [trunk revision 264170] This is a regression, as there are no issues with either GCC 8 or with gcc (Debian 20180822-1) 9.0.0 20180822 (experimental) [trunk revision 263760] When building the MPFR trunk revision 13165 with ./configure --enable-assert=full CC=gcc-snapshot CFLAGS="-O2" (no issues with -O or with -O2 -fsanitize=undefined -fno-sanitize-recover), I get a failure in tstrtofr: Check overflow failed (2) with: s='' x=0 I've modified MPFR's strtofr.c to the following (i.e. adding printf's): [...] long read_exp = strtol (str + 1, &endptr, 10); if (endptr != str+1) str = endptr; sum = read_exp < MPFR_EXP_MIN ? (str = endptr, MPFR_EXP_MIN) : read_exp > MPFR_EXP_MAX ? (str = endptr, MPFR_EXP_MAX) : (mpfr_exp_t) read_exp; printf ("%ld %d\n", sum, res); printf ("%ld\n", pstr->exp_base); MPFR_SADD_OVERFLOW (sum, sum, pstr->exp_base, mpfr_exp_t, mpfr_uexp_t, MPFR_EXP_MIN, MPFR_EXP_MAX, res = 2, res = 3); // printf ("%ld %d\n", sum, res); [...] and reduced tstrtofr.c to: #include "mpfr-test.h" static void check_overflow (void) { mpfr_t x; char *s; mpfr_init (x); mpfr_strtofr (x, "123456789E9223372036854775807", &s, 0, MPFR_RNDN); if (s[0] != 0 || !MPFR_IS_INF (x) || !MPFR_IS_POS (x) ) { printf ("Check overflow failed (2) with:\n s='%s'\n x=", s); mpfr_dump (x); exit (1); } mpfr_clear (x); } int main (int argc, char *argv[]) { tests_start_mpfr (); check_overflow (); tests_end_mpfr (); return 0; } I get the following failure: 9223372036854775807 1 9 Check overflow failed (2) with: s='' x=0 Then, if I uncomment the last printf line, the failure disappears, and I get: 9223372036854775807 1 9 9223372036854775807 2
I could simplify the code: #include <stdio.h> #include <stdlib.h> struct s { long e; }; static void f (struct s *ps) { volatile long m = 9223372036854775807; const char *str = "11E"; int r; long sum; ps->e = 0; for (;;) { if (*str++ != '1') break; ps->e ++; } r = 1; sum = m; printf ("%ld\n", sum); if (sum >= 0 && ps->e >= 0) { unsigned long uc; uc = (unsigned long) sum + (unsigned long) ps->e; if (uc > 9223372036854775807) r = 2; else sum = 17; } else sum = sum + ps->e; printf ("%ld\n", sum); printf ("%d\n", r); if (r != 2) exit (1); ps->e = sum; } int main (void) { struct s s; f (&s); return 0; } $ gcc-snapshot -O2 tst.c -o tst $ ./tst 9223372036854775807 17 1 zsh: exit 1 ./tst instead of 9223372036854775807 9223372036854775807 2
The bug was introduced in r263875.
Note: This may yield security issues since basically, this makes integer overflow detection fail. In the testcase, after unsigned long uc; uc = (unsigned long) sum + (unsigned long) ps->e; uc > 9223372036854775807, i.e. uc > LONG_MAX, is regarded as false instead of true.
I will have a look.
This is really a duplicate of PR86554. We're performing code-hoisting on sum + ps->e in the following bit: if (sum >= 0 && ps->e >= 0) { unsigned long uc; uc = (unsigned long) sum + (unsigned long) ps->e; if (uc > 9223372036854775807) r = 2; else sum = 17; } else sum = sum + ps->e; Inserting expression in block 5 for code hoisting: {plus_expr,_8,sum_9} (0008) Inserted _36 = _8 + sum_9; in predecessor 5 (0008) because at some point I teached value-numbering that the two expressions compute the same value and GCC transforms if (uc > 9223372036854775807) to if ((signed long)uc < 0). The testcase works correctly with -fno-code-hoisting. Not sure why the cited rev. triggers it but as seen with the other PR the underlying issue (hoisting an expression with undefined behavior) is latent. After code-hoisting later VRP pass will optimize the compare (as expected), so -fno-tree-vrp also is a workaround. *** This bug has been marked as a duplicate of bug 86554 ***
Note concerning the tests: in Debian, as of gcc-snapshot 1:20181209-1, MPFR is no longer affected (and I've checked that the failure is still reproducible with gcc-snapshot 1:20181127-1). But the testcase in Comment 1 still fails.