Whether or not a program is broken is defined by the specification, not by "do real programs do this". The specification has no objections with this program.
Nothing an implementation does in response to an attempt to dereference a round-tripped pointer could render it non-conforming. An cases where two equal pointers could exist which would be usable only to access disjoint sets of objects, a capricious but conforming implementation could make any conversion of a round-tripped pointer yield a pointer which would compare equal to the original, but would not be usable to access any of the same objects. So in that sense, almost all programs that make use of integer-to-pointer conversions would be "broken" unless they are only intended for use on implementations that uphold guarantees stronger than what the Standard requires.
That having been said, if the example were changed slightly:
#include <stdint.h>
char x[1], y[1] = {0};
int test(unsigned char *p)
{
uintptr_t ip = (uintptr_t)p;
uintptr_t iq = (uintptr_t)(x+1);
y[0] = 123;
if (iq == ip) {
*p = 45;
}
return y[0];
}
Here the code never dereferences the round-tripped pointer, but clang still processes the code nonsensically.
What's going on is similar to the way clang and gcc treat some goofy corner cases in the Standard involving restrict
-qualified pointers, which would cause the C Standard would define the behavior of a construct of the form (someFlag && a || b) && doSomething)
when a
is 0 (meaning someFlag
would be evaluated but doSomething
would be unconditionally skipped) or when b
is 1 (meaning someFlag
would be evaluated but doSomething
would be unconditionally executed), and yet not define program behavior in cases where execution of doSomething
is conditioned on someFlag
. I can't think of any reasonable abstraction model in which the reason for a compiler to decide to execute or skip a piece of code would play any role in determining whether its behavior is defined, but that's how the Standard specifies the behavior of restrict
, and clang and LLVM are simply applying the same logic elsewhere.