https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86884

            Bug ID: 86884
           Summary: aggressive loop optimization and effective type
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

As requested in https://gcc.gnu.org/ml/gcc-patches/2018-08/msg00514.html, for
the following (undefined) C test case, the aggressive loop optimization
determines the upper bound of the loop to be 3 based on the size of X::c.  As a
result, the loop is eliminated and the call to abort is made unconditionally
even though the representation of the object stored in memory is a
nul-terminated string of 15 characters, and so the number of characters at p->c
before the final nul is 11.

The test case is undefined because the object of type struct Y is being
accessed by an lvalue of type struct X, and the array at p->c is not
nul-terminated so the loop accesses memory beyond the end of p->c.  That the
effective type of the object ar p may actually be struct Y is not relevant (or
considered).  But according to the discussion at the thread above, even though
this is undefined in C, it's apparently meant to be well-defined in GIMPLE.

$ cat e.c && gcc -O2 -S -Wall -fdump-tree-cddce1=/dev/stdout e.c
struct X { int i; char c[4]; int j;};
struct Y { char c[16]; };

void f (struct X *p)
{
  struct Y y = { "012345678901234" };
  __builtin_memcpy (p, &y, sizeof (struct Y));

  // *p's effective type is now struct Y

  int n = 0;
  while (p->c[n])
    ++n;

  if (n < 7)
    __builtin_abort ();
}

Marking useful stmt: MEM[(char * {ref-all})p_6(D)] =
0x343332313039383736353433323130;

Marking useful stmt: __builtin_abort ();

Found loop 1 to be finite: upper bound found.

Processing worklist:
processing: __builtin_abort ();

processing: MEM[(char * {ref-all})p_6(D)] = 0x343332313039383736353433323130;


Eliminating unnecessary statements:
Deleting : n_9 = n_2 + 1;

Deleting : if (_1 != 0)

Deleting : _1 = p_6(D)->c[n_2];
...
fix_loop_structure: removing loop 1
f (struct X * p)
{
  __int128 unsigned y;
  int n;
  struct Y y;

  <bb 2> :
  MEM[(char * {ref-all})p_6(D)] = 0x343332313039383736353433323130;
  __builtin_abort ();

}

Reply via email to