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 ();
}