pete said:
I don't think trap representations
have anything to do with freed pointers.
I think we're dealing with the case of
accessing a pointer with unspecified value,
and that access being undefined.
The standard doesn't say the value is unspecified; it says it's
indeterminate.
"An unspecified value cannot be a trap representation."
Right, so the two cases are mutually exclusive (presumably at the whim
of the implementation).
"The value of a pointer becomes indeterminate when
the object it points to reaches the end of its lifetime."
Right, meaning it's *either* unspecified *or* a trap representation.
The standard could have been more specific, requiring it to be a trap
representation, but the same bit pattern (address) could later be
returned by another call to malloc(), and a program could detect this
using memcmp().
So:
int *ptr = malloc(sizeof *ptr); /* assume ptr != NULL */
free(ptr);
/*
* ptr now has an indeterminate value, possibly a trap representation
*/
ptr; /* undefined behavior */
The tricky thing is that the value can be unspecified rather than a
trap representation. For example, this program *might* examine the
indeterminate value of ptr1 without invoking undefined behavior:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
int main(void)
{
void *ptr1;
void *ptr2;
ptr1 = malloc(32);
assert(ptr1 != NULL);
free(ptr1);
ptr2 = malloc(32);
assert(ptr2 != NULL);
if (memcmp(&ptr1, &ptr2, sizeof ptr1) == 0) {
printf("The same address was re-used\n");
printf("ptr1 = %p\n", ptr1);
}
else {
printf("The address was not re-used\n");
printf("Examining ptr1 may invoke undefined behavior\n");
}
return 0;
}
But if we drop the second malloc() call, after free(ptr1) the object
ptr1 *could* hold a trap representation. (The set of representations
that are trap representations can vary over time during the execution
of the program.)