IIRC, one justification for this was to account for systems with non-flat memory where inspecting the value of the old pointer might cause a processor exception.
IIRC, one justification for this was to account for systems with non-flat memory where inspecting the value of the old pointer might cause a processor exception.
This is legal. But dereferencing old_pointer even after this check had passed is undefined.
C89 says that "The value of a pointer that refers to freed space is indeterminate." and that behavior is undefined "upon use ... of indeterminately-valued objects", hence a compiled program can e.g. behave as if `new_pointer == old_pointer` even though the object was relocated in memory.
Using clang, program #1:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
void * p = malloc(123);
void * q = realloc(p, 200);
printf("%p == %p -> %i\n", p, q, p == q);
free(q);
printf("%p\n", q);
return 0;
}
prints out: 0x5f867a8a9300 == 0x5f867a8a9300 -> 1
0x5f867a8a9300
Program #2: (only difference is the extra printf after malloc) #include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
void * p = malloc(123);
printf("%p\n", p);
void * q = realloc(p, 200);
printf("%p == %p -> %i\n", p, q, p == q);
free(q);
printf("%p\n", q);
return 0;
}
prints out: 0x5bcba8225300
0x5bcba8225300 == 0x5bcba82257a0 -> 0
0x5bcba82257a0
So if we print out the pointer before reallocation then they're not equal, but if we don't then they are equal.Funny enough, "-fsanitize=undefined" doesn't seem to detect this. Neither does "-fsanitize=address" (but with ASAN the results are now consistent and in both cases compare to not equal).
But the malloc/free interface is one of the most badly designed interfaces in the C lang it's not even funny
More literally, your pointer value is copied into a register before the call into libc, so free can't change the value even if it wants to. Realloc can't either for the same reason.
That provenance has come up with the premise that a ! = a for a 64bit integer value is an error in the formalism, specifically the language is deliberately inventing things that cannot be so on hardware.
So what? The standard has "undefined behavior"; real implementations always do something, even if that something cannot be determined in advance. The standard is the standard, it's not a machine.
I don't know what modern C is for. The one that manipulates an abstract machine with concurrency oracles and time travelling metadata on object identifiers. It looks like an aberration derived from C++ to me.
That wheel is certainly in need of some serious reinvention anyway. This seems like a good starting point: