After some painful experiences, I understand the problem of dangling pointers and double free. I am seeking proper solutions.
aStruct
has a number of fields including other arrays.
aStruct *A = NULL, *B = NULL;
A = (aStruct*) calloc(1, sizeof(sStruct));
B = A;
free_aStruct(A);
...
// Bunch of other code in various places.
...
free_aStruct(B);
Is there any way to write free_aStruct(X)
so that free_aStruct(B)
exits gracefully?
void free_aStruct(aStruct *X) {
if (X ! = NULL) {
if (X->a != NULL) { free(X->a); x->a = NULL; }
free(X); X = NULL;
}
}
Doing the above only sets A = NULL
when free_aStruct(A);
is called. B
is now dangling.
How can this situation be avoided / remedied? Is reference counting the only viable solution? Or, are there other "defensive" approaches to freeing memory, to prevent free_aStruct(B);
from exploding?
In plain C, the most important solution to this problem is discipline, because the root of the problem is here:
B = A;
Making a copy of the pointer without changing anything within your struct, circumventing whatever you use without any warning from the compiler. You have to use something like this:
B = getref_aStruct(A);
The next important thing is to keep track of the allocations. Some things that help are clean modularization, information hiding and DRY -- Don't Repeat Yourself. You directly call calloc() to allocate the memory while you use a free_aStruct() function to free it. Better use a create_aStruct() to allocate it. This keeps things centralized and in one place only, instead of throwing memory allocations all over your codebase.
This is a much better base for whatever memory tracking system you build on top of this.