Bug 87276 - [9 Regression] Buggy tree-ssa optimization introduced in revision 263875
Summary: [9 Regression] Buggy tree-ssa optimization introduced in revision 263875
Status: RESOLVED DUPLICATE of bug 86554
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 9.0
Assignee: Richard Biener
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-09-11 01:17 UTC by Vincent Lefèvre
Modified: 2019-01-04 13:33 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-09-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2018-09-11 01:17:11 UTC
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
Comment 1 Vincent Lefèvre 2018-09-11 12:39:18 UTC
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
Comment 2 Vincent Lefèvre 2018-09-11 21:14:58 UTC
The bug was introduced in r263875.
Comment 3 Vincent Lefèvre 2018-09-11 21:24:32 UTC
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.
Comment 4 Richard Biener 2018-09-12 07:59:55 UTC
I will have a look.
Comment 5 Richard Biener 2018-09-12 12:48:25 UTC
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 ***
Comment 6 Vincent Lefèvre 2019-01-04 13:33:10 UTC
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.