Is the compiler allowed to recycle freed pointer variables?
It has been claimed that
a compiler is free to reuse the pointer variable for some other purpose after
the reallocbeing freed, so you have no guarantee that it has the same value as it did before
ie
void *p = malloc(42);
uintptr_t address = (uintptr_t)p;
free(p);
// [...] stuff unrelated to p or address
assert((uintptr_t)p == address);
might fail.
C11 annex J.2 reads
The value of a pointer that refers to space deallocated by a call to the free or realloc function is used (7.22.3) [is undefined]
but the annex is of course not normative.
Annex L.3 (which is normative, but optional) tells us that if
The value of a pointer that refers to space deallocated by a call to the free or realloc function is used (7.22.3).
the result is permitted to be critical undefined behaviour.
This confirms the claim, but I'd like to see an appropriate quote from the standard proper instead of the annex.
Upon an object reaching the end of its lifetime, all pointers to it become indeterminate. This applies to block-scope variables and to malloced memory just the same. The applicable clause is, in C11, 6.2.4:2.
The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.
Using indeterminate memory for anything, including apparently harmless comparison or arithmetic, is undefined behavior (in C90; later standards complicate the matter terribly but compilers continue to treat usage of indeterminate memory as undefined behavior).
As an example, how about the following program printing that p
and q
are both different and the same? The results of execution with various compilers are shown here.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(int argc, char *argv[]) {
char *p, *q;
uintptr_t pv, qv;
{
char a = 3;
p = &a;
pv = (uintptr_t)p;
}
{
char b = 4;
q = &b;
qv = (uintptr_t)q;
}
printf("Roses are red,\nViolets are blue,\n");
if (p == q)
printf ("This poem is lame,\nIt doesn't even rhyme.\n");
else {
printf("%p is different from %p\n", (void*)p, (void*)q);
printf("%"PRIxPTR" is not the same as %"PRIxPTR"\n", pv, qv);
}
}