I was having a discussion regarding using variables with indeterminate values leading to unspecified behavior, rather than undefined behavior, as discussed here. This assuming that a variable with automatic storage duration has its address taken and that trap representations do not apply.
In the specific case it was discussed what happens to ptr
after free(ptr)
, in which case C17 6.2.4 applies:
The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.
I made this example:
#include <stdlib.h>
#include <stdio.h>
int main (void)
{
int* ptr = malloc(sizeof *ptr);
int* garbage;
int*volatile* dummy = &garbage; // take the address
free(ptr);
puts("This should always print");
fflush(stdout);
if(ptr == garbage)
{
puts("Didn't see that one coming.");
}
else
{
puts("I expect this to happen");
}
puts("This should always print");
}
The argument I was making was that in theory, we can't know if ptr == garbage
is true or false since they are both indeterminate at that point. And so the compiler need not even read those memory locations - since it can deduct that both pointers hold indeterminate values, it is free to evaluate the expression to either true or false as it pleases during optimization. (In practice most compilers probably don't do that.)
I tried the code on x86_64 compilers gcc, icx and clang 14 -std=c17 -pedantic-errors -Wall -Wextra -O3
, in all cases I got the output:
This should always print
I expect this to happen
This should always print
However, in clang 15 specifically, I get:
This should always print
This should always print
Followed by error code 139 seg fault.
https://godbolt.org/z/E6xTzc156
If I comment out the "This should always print"/fflush
lines, clang 15 makes a dummy executable with the disassembly only consisting of a label:
main: # @main
Even though main() is containing several side effects.
Question:
Why does clang 15 behave differently than older versions/other compilers? Does it implement trap representations for pointers on the x86_64 I was playing around with or something similar?
Assuming there are no trap representations, none of this code should contain undefined behavior.
EDIT
Regarding how indeterminate values that are not trap representations should be expected to (not) behave, this has been discussed at length in DR 260 and DR 451. The Committee wouldn't be having these long and detailed discussions if the whole thing was to be dismissed as "it is undefined behavior".