It's known that the value of a pointer to an object becomes indeterminate after the object is dead (C11, 6.2.4p2). Whether its representation becomes indeterminate is up for debate but let's bypass the issue by saving the representation while the object is still alive. For example, we can cast it to an integer. And we'll get an ordinary integer, with a stable value etc., not affected by changes in the life of the original object. Right? This seems to be broken for the equality operators when the operands are constructed from addresses of automatic variables and at least one of these variables is dead at the time of comparison. ---------------------------------------------------------------------- #include <stdio.h> int main() { unsigned long u, v; { int x[5]; u = (unsigned long)x; } { int y[5]; v = (unsigned long)y; } printf("u = %#lx\n", u); printf("v = %#lx\n", v); printf("diff = %#lx\n", u - v); printf("eq = %d\n", u == v); } ---------------------------------------------------------------------- $ gcc -std=c11 -pedantic -Wall -Wextra -O3 test.c && ./a.out u = 0x7ffeb6326180 v = 0x7ffeb6326180 diff = 0 eq = 0 ---------------------------------------------------------------------- gcc x86-64 version: gcc (GCC) 10.0.0 20191219 (experimental) If "diff == 0" then "eq" should be 1.
clang bug -- https://bugs.llvm.org/show_bug.cgi?id=44342 There is a second example there, with memcpy/memcmp, but it doesn't trigger the bug in gcc so not pasting it here. (Generally gcc seems to be much less consistent than clang in optimizing integers vs. memcpy/memcmp.)
But gcc seems to be better than clang in arranging compound literals in memory so here is a gcc-only testcase with them: ---------------------------------------------------------------------- #include <stdio.h> int main() { unsigned long u, v; { u = (unsigned long)&(int){0}; } { v = (unsigned long)&(int){0}; } printf("diff = %lu\n", u - v); printf("eq = %d\n", u == v); } ---------------------------------------------------------------------- $ gcc -std=c11 -pedantic -Wall -Wextra -O3 test.c && ./a.out diff = 0 eq = 0 ---------------------------------------------------------------------- gcc x86-64 version: gcc (GCC) 10.0.0 20191230 (experimental) ----------------------------------------------------------------------
I'm not sure GCCs behavior is non-conforming here. What happens is that we compute u == v at compile-time, combining stmts from <bb 2> : D.2438 = 0; u_6 = (long unsigned int) &D.2438; D.2438 ={v} {CLOBBER}; D.2439 = 0; v_9 = (long unsigned int) &D.2439; D.2439 ={v} {CLOBBER}; _1 = u_6 - v_9; printf ("diff = %lu\n", _1); _2 = u_6 == v_9; _3 = (int) _2; printf ("eq = %d\n", _3); _13 = 0; return _13; but we can't compute a definitive value for the difference so that gets computed at runtime where stack layouting happens to place D.2438 and D.2439 at the same address. So the inconsistency is that GCC first assumes no such thing as stack slot sharing happens but then does it anyways. I guess we'd be allowed to optimize u - v to an arbitrary constant(?) but then enough trickery can expose the "real" values again (and the "inconsistency"). I see no good way "fixing" GCC here without sacrifying normal usage for this arcane case.