First, to clarify, I am not talking about dereferencing invalid pointers!
Consider the following two examples.
Example 1
typedef struct { int *p; } T;
T a = { malloc(sizeof(int) };
free(a.p); // a.p is now indeterminate?
T b = a; // Access through a non-character type?
Example 2
void foo(int *p) {}
int *p = malloc(sizeof(int));
free(p); // p is now indeterminate?
foo(p); // Access through a non-character type?
Question
Do either of the above examples invoke undefined behaviour?
Context
This question is posed in response to this discussion. The suggestion was that, for example, pointer arguments may be passed to a function via x86 segment registers, which could cause a hardware exception.
From the C99 standard, we learn the following (emphasis mine):
[3.17] indeterminate value - either an unspecified value or a trap representation
and then:
[6.2.4 p2] The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime.
and then:
[6.2.6.1 p5] Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. If such a representation is produced by a side effect that modifies all or any part of the object by an lvalue expression that does not have character type, the behavior is undefined. Such a representation is called a trap representation.
Taking all of this together, what restrictions do we have on accessing pointers to "dead" objects?
Addendum
Whilst I've quoted the C99 standard above, I'd be interested to know if the behaviour differs in any of the C++ standards.
free
does not modify its argument. The pointer passed tofree
still points to the same location afterwards. The call tofree
simply informs the standard library that the object is no longer 'in use' and the storage at that location can be re-used. This is not the same as the object 'reaching the end of its lifetime', which occurs for objects on the stack. – Varixmalloc
andfree
, I guess that an implementation is not permitted to give them special treatment. – Varixmalloc
andfree
invokes undefined behavior already. 7.1.3: "If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined." – FaythcustomMalloc()
andcustomFree()
- in which case object lifetime would be unaffected. – Varix"Allocated storage is described in 7.22.3"
. In other words, allocated storage is a special case where 6.2.4 doesn't necessarily apply. – AnalliseThe lifetime of an allocated object extends from the allocation until the deallocation.
That line seems to go well together with the text you cited from 6.2.4. – Anallise