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