https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103343
Bug ID: 103343 Summary: Invalid codegen when comparing pointer to one past the end and then dereferencing that pointer Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: gabravier at gmail dot com Target Milestone: --- extern int x[1], y; int f(int *p, int *q) { *q = y; if (p == (x + 1)) { *p = 2; return y; } return 0; } GCC trunk currently outputs the following code with -O3: f: mov eax, DWORD PTR y[rip] mov DWORD PTR [rsi], eax cmp rdi, OFFSET FLAT:x+4 je .L5 xor eax, eax ret .L5: mov DWORD PTR x[rip+4], 2 ret Which is incorrect because `p` could point to `y`, for example if `f` was called as such: int whatever; f(&y, &whatever); and `y` could happen to be located in memory right after `x`. Also, although the comparison invokes unspecified behavior, this still means only two results are possible according to the standard: - if `p == (x + 1)` results in `false`, then the result of `f` is 0 - if `p == (x + 1)` results in `true`, then the result of `f` is 2 since we do `*p = 2` and `p` points to `y`. GCC's optimization makes it so the result can also be the previous value of `y`, which could be something else than 0 or 2. It seems that GCC assumes that because `p == (x + 1)` it can replace all occurrences of `p` with `x + 1` without any regard to provenance, and doing that change manually would indeed mean the `return y;` could be optimized to use the previous store (and the store to `x + 1` would be UB, too...), but this isn't the case here: `p` could simultaneously validly point to `y` and be equal to `x + 1`. PS: This also results in plenty of invalid warnings when compiling with -Wall: <source>: In function 'f': <source>:6:9: warning: array subscript 1 is outside array bounds of 'int[1]' [-Warray-bounds] 6 | *p = 2; | ^~ <source>:1:12: note: at offset 4 into object 'x' of size 4 1 | extern int x[1], y; | ^