Background info: My program involves creating a hash table and one of my functions is free_hash(struct hash_table *table)
.
struct hash_table *table
points to an array of struct hash_entry
pointers. To test my free_hash
function in main
I have a void *test_free = what
. the declaration and initialization for what
is hash_table *what = new_hash(array_size)
.
this is struct hash_table *new_hash()
it returns a function that returns a pointer to a new initialized struct hash_table
.
My question: After freeing what
, eg.free_hash(what)
, what happens to test_free
. What is the address of it/the value of what it is pointing at. And is there any other way I can make sure that what
has been destructed/freed.
CodePudding user response:
test_free
and what
are pointers. The value they have is basically an address. And you assigned the same address to both of them. Nothing happens to either variable once you free that to which they point.
Once you do, the pointers are deemed to be indeterminate, so it becomes undefined behaviour to deference either one. But there's nothing in either variable that indicates this. The onus is on the programmer to ensure no attempts is made to access a freed structure.
As for checking if everything was properly freed, there's -fsanitize=address
, valgrind
, etc.
CodePudding user response:
C 2018 6.2.4 2 says “… The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.” When you release memory with free
, the lifetime of any objects in it end, so any pointers to this memory become indeterminate. “Indeterminate” means the pointer value is not even fixed; it may act as if it has a different value each time it is used.
This rule exists because there have been C implementations in which maintaining pointers required auxiliary information associated with the allocated memory. So the “value” of a pointer was not represented just by the bits directly in the memory used for the pointer object itself. Once the memory, and its auxiliary information, are released, it might no longer be possible to interpret the value of the pointer correctly.
In most modern C implementations, addresses are implemented simply as numbers in a “flat” address space. In this case, no auxiliary information is needed to interpret the value of a pointer or to work with it as by adding offsets to it. However, because the rule exists, optimizers in compilers may treat any pointer to freed memory as indeterminate.
For example, in this code:
void *x;
free(p);
if (SomeTest)
x = p;
else
x = q;
printf("%p\n", x);
the compiler is allowed to optimize this to:
void *x;
free(p);
x = q;
printf("%p\n", x);
even if SomeTest
is true. That is the fact that p
is indeterminate after free
means it is allowed to have any value, so it could have the value of q
, so the if
statement would just be:
if (SomeTest)
x = q;
else
x = q;
which of course can be optimized to x = q;
.
In short, once you release memory, the C standard does not give you any assurance your program will behave as if a pointer to that memory has any particular value. It may act as if the pointer has a different value each time the program uses it.