https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65752
--- Comment #25 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Chung-Kil Hur from comment #24) > (In reply to schwab from comment #23) > > "gil.hur at sf dot snu.ac.kr" <gcc-bugzi...@gcc.gnu.org> writes: > > > > > Since "hello" is not printed, I think the if-statement is the same as > > > no-op. > > > Thus, removing the if-statement should not change the behavior of the > > > program > > > according to ISO C11. > > > > Unless you are invoking undefined behaviour. > > > > Andreas. > > ============================== > #include <stdio.h> > > int main() { > int x = 0; > uintptr_t xp = (uintptr_t) &x; > uintptr_t i, j; > > for (i = 0; i < xp; i++) { } > j = i; > > *(int*)((xp+i)-j) = 15; > > printf("%d\n", x); > } > ============================= > > This prints "15". > And I do not think there is any UB. > Please correct me if I am wrong. > > Then, I add the if-statement. > > ============================== > #include <stdio.h> > > int main() { > int x = 0; > uintptr_t xp = (uintptr_t) &x; > uintptr_t i, j; > > for (i = 0; i < xp; i++) { } > j = i; > > /****** begin *******/ > if (j != xp) { > printf("hello\n"); > j = xp; > } > /****** end *********/ > > *(int*)((xp+i)-j) = 15; > > printf("%d\n", x); > } > ============================= > > This prints "0" without printing "hello". > > Thus, this raises no UB unless "j != xp" raises UB. > > If you think "j != xp" raises UB, please explain why and give some reference. > > Otherwise, I think it is a bug of GCC. The C standard only guarantees that you can convert a pointer to uintptr_t and back, it doesn't guarantee that you can convert a modified uintptr_t back to a pointer that is valid. Thus, doing (int *)((xp + i) - j) is invoking undefined behavior. That you see an effect of this undefined behavior just with the added if is because that if confuses early GCC optimizations which would have cancelled i - j to zero, retaining (int *)xp. Instead it enables later optimization to see that xp - j cancels and thus it is left with (int *)i. This is because you are essentially computing (xp + xp) - xp == xp but dependent on what two pieces get cancelled the pointer is based on either xp (ok) or on i (not ok - that is related to xp only via an implicit equivalency). The net result is that I can't see how to "detect" this kind of situation in points-to analysis in a way that does not pessimize all pointer-to-integer / integer-to-pointer conversions. In theory it would be possible to add a flag similar to -fno-strict-aliasing to do this pessimization (but there is already -fno-tree-pta which avoids the issue as well). So in the end my conclusion is that either the testcase invokes undefined behavior or the C standard has a defect. Thus the bug is WONTFIX unless somebody can come up with a way to handle these kind of equivalences in the points-to algorithm in GCC in a way not pessimizing everything. One might consider an incomplete approach like that in comment #6 but I am not convinced about this hack (and one would need to evaluate its effects on code generation).