https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65752
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |law at gcc dot gnu.org --- Comment #32 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Chung-Kil Hur from comment #29) > Dear Richard, > > This time, I think I constructed a real bug. > Please have a look and correct me if I am wrong. > > ===================== > #include <stdio.h> > > int main() { > int x = 0; > uintptr_t xp = (uintptr_t) &x; > uintptr_t i; > > for (i = 0; i < xp; i++) { } > > *(int*)xp = 15; > > printf("%d\n", x); > } > ===================== > > This program prints "15" and I do not think this raises UB. > > Now I add an if-statement to the program. > > ===================== > #include <stdio.h> > > int main() { > int x = 0; > uintptr_t xp = (uintptr_t) &x; > uintptr_t i; > > for (i = 0; i < xp; i++) { } > > /*** begin ***/ > if (xp != i) { > printf("hello\n"); > xp = i; > } > /*** end ***/ > > *(int*)xp = 15; > > printf("%d\n", x); > } > ===================== > > This program just prints "0". > > Since "hello" is not printed, the if-statement is not executed. > However, it prints a different result than before, which I think is a bug. It indeed is a more unfortunate case but you are still breaking the dependency chain in the if (xp != i) code by assigning i to xp. The code is never executed (which is why this is unfortunate) and I am less than 100% sure it still invokes undefined behavior. The unfortunate thing is that the equivalence you build on the 'else' path (xp == i) is used by the compiler to replace xp by i on the *(int*)xp = 15 line getting us into the very same situation as in all other cases. That is, we have if (xp != i) ... # xp = PHI <xp, i> *(int *)xp = 15; because of the conditional and in this case our phiopt pass optimizes that to # xp = PHI <i, i> instead of the equally valid # xp = PHI <xp, xp> other passes (dom) may end up doing a similar thing (at least for GCC 5 and the particular testcase we are lucky here though), but for GCC 5 -fdisable-tree-phiopt1 -fdisable-tree-phiopt2 avoids the issue. Generally there is no good way to determine which choice is better. What the PTA code does is sensible btw. For # xp_20 = PHI <0(2), xp_7(7)> xp_7 = xp_20 + 1; if (xp_6 > xp_7) goto <bb 7>; else goto <bb 4>; <bb 7>: goto <bb 3>; the PTA constraints are xp_6 = &x xp_20 = &NULL xp_20 = xp_7 xp_7 = xp_20 xp_7 = &NONLOCAL which means PTA considers that all pointers coming from integer constants point to global memory only (that's to support fixed address objects). That helps to avoid false aliasing to stack objects and avoids the need to make all locals escaped when you have code passing an integer to a function (that integer, converted to a pointer _could_ point to a stack slot in the caller, no?!). So 'i' is considered to eventually point to arbitrary global memory. But _not_ to arbitrary address-taken locals.