Keith Thompson <Keith.S.Thompson+
u@gmail.com> writes:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
[...]
>
There is an important distinction here, one I suspect you are
either glossing over or missing. The bits in the pointer don't
change, but the meaning of those bits can change. To say that a
different way, what memory location a pointer object representation
(the bits) designates can depend on information outside the pointer
object itself, depending on the machine architecture. A natural
example is a machine with segmented memory, where "a pointer"
consists of a segment number and an offset within the segment. If
a free() has been done by marking a particular segment invalid
(such as by setting a bit in a global segment table), the bits in
the pointer passed to free() don't change, but those bits no longer
refer to any memory location. The pointer becomes "indeterminate"
even though none of the bits in the pointer have changed. Does
that make sense?
>
A quibble: it's the pointer *value* that becomes indeterminate,
not the pointer object. After free(p), p is still a valid pointer
object; you can take its address, store a new value in it, etc.
You just can't read its value without undefined behavior. Note
also that the argument to free() needn't be an lvalue; there
might not be an object holding the value that was passed to
free().
I appreciate that you are trying to point out a subtle distinction,
but I think what you're saying hurts the discussion rather than
helps it. First the context of the discussion was whether about
bits /in an object/ can change; there is no reason to worry about
the distinction between the bits in memory and the memory itself,
which is perfectly clear given the context. Second what you're
saying glosses over a much more important distinction, and one that
the C standard itself is confused about, which is the two senses of
the word "value" as this term is used in the C standard. Taking
the phrasing used in n1570, a "value" can be an indeterminate
value only if the "value" is stored in an object, because whether a
"value" is a trap representation is defined in terms of object
repreresentations, and by definition object representations occur
only within objects. An abstract value that lives outside of any
object thus cannot be a trap representation, and hence must be
a valid value (even if it might be an unspecified value). The case
you're talking about where a "pointer value" becomes indeterminate
is meaningful only if bits representing the "pointer value" have
been stored in some object, because the possibility of being a
trap represention doesn't occur except as the contents of an object.
As for free() not changing the bits in the pointer, I'm only
mostly sure that's guaranteed. On one hand, "An object exists,
has a constant address, and retains its last-stored value
throughout its lifetime.", which suggests that the bits don't
change. On the other hand, a program with defined behavior can't
tell whether the value changed, since it can't examine the pointer
value. On the other other hand, a program can tell whether the
representation changed by examining the pointer object as an array
of unsigned char.
We don't care whether the "value" of a pointer (being held in an
object) changes; the conversation is about whether the bits (held
in an object) change, and whether the bits change can easily be
determined by code that doesn't have undefined behavior, by using
unsigned char to access the bytes of the object.
Can free(p) cause the representation of p to become what C23 calls
a "non-value representation", and what earlier editions called a
"trap representation"? If so, one could argue that p doesn't have
a "value", and perhaps the "last-stored value" wording doesn't
apply.
That is yet another sense of the word "value". Copying bytes into
a pointer object by means of memcpy() or an unsigned char array
surely means the pointer object has a "last-stored value". When a
valid pointer value is stored in a pointer object, it just as
surely has a "last-stored value" that can be read using memcpy()
or an unsigned character array, and it is that "value" that we
are interested in.
I don't expect any implementation to do anything to the bits of a
pointer object whose value is passed to free(), but I'm wondering
whether an implementation that does so could be conforming.
The discussions that have happened around "indeterminate values"
demonstrate that there is confusion and uncertainty about what is
meant by the C standard, even among members of the ISO C committee.
I think the best that can be said on this issue is that the standard
needs revising before the question has a meaningful answer. Until
that happens, I am happy to say that any implementation where those
bits do change is non-conforming, or alternatively is one that
should be avoided like the plague.