Keith Thompson said:
A compiler could treat the free() function specially, but it's unlikely
that
char *p = malloc(10);
if (p ! NULL) {
p ++;
free(p-1);
}
would modify the representation if p.
Furthermore, the bytes that make up the representation of p are
themselves objects which "retain their last-stored values between
program startup and program termination".
On the other hand, I seem to recall that there's a DR that says free()
*can* change the representation of a pointer object after its value is
passed to free(). I'll try to track it down later.
It's C99 DR #260, submitted by Clive D.W. Feather in 2004.
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm
As far as I can tell, the DR didn't lead to any specific wording in the
C11 standard, but the committee response was:
Question 1:
Values may have any bit-pattern that validly represents them
and the implementation is free to move between alternate
representations (for example, it may normalize pointers,
floating-point representations etc.). In the case of an
indeterminate value all bit-patterns are valid representations
and the actual bit-pattern may change without direct action of
the program.
Question 2:
If two objects have identical bit-pattern representations and
their types are the same they may still compare as unequal
(for example if one object has an indeterminate value) and if
one is an indeterminate value attempting to read such an object
invokes undefined behavior. Implementations are permitted to
track the origins of a bit-pattern and treat those representing
an indeterminate value as distinct from those representing a
determined value. They may also treat pointers based on different
origins as distinct even though they are bitwise identical.
In reference to "Question 1", I agree that it makes sense to permit an
implementation to normalize pointers and floating-point objects when two
or more representations have the same value. I wrote above that the
bytes making up the representation of an object are themselves objects,
which are required by 6.2.4p2 to "retain[] its last-stored value
throughout its lifetime".
I'm no longer quite as sure of that, given the way 6.2.6.1 defines
*object representation*:
Values stored in non-bit-field objects of any other object type
consist of n × CHAR_BIT bits, where n is the size of an object
of that type, in bytes. The value may be copied into an object
of type unsigned char [n] (e.g., by memcpy); the resulting set
of bytes is called the *object representation* of the value.
which talks about the bytes *after copying them from the object*,
so at least that paragraph doesn't imply that the bytes within the
object itself are objects.
On the other hand, an object is defined as a "region of data storage in
the execution environment, the contents of which can represent values";
a byte within a pointer object, for example, would seem to qualify.
On the other other hand, a program that depends on a byte within a freed
pointer retaining its previous value would be perverse, and I don't feel
*too* bad about the possibility of breaking it.