Reputation: 1492
I was reading to Dangling Pointer and found it's a good habit do this, to prevent oneself from dangling pointer error.
free(ptr); // free the ptr
ptr = NULL;
Now I decided to test this with a sample vanilla C code.
CASE_1
char *ptr = malloc(10);
...
...
free(ptr);
ptr=NULL;
// Just to check what happen if I call free more than I once
free(ptr)
ptr=NULL;
All work fine. Until I decided to wrap the free
and the pointer NULL
assignment in a function
I named it safefree
void safefree(char *pp) {
free(pp);
pp = NULL;
}
CASE_2
Now, when I ran the above method more than 1 (like this)
safefree(ptr);
safefree(ptr);
I get the following error.
malloc: *** error for object 0x7fd98f402910: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
I happen to understand the error (pointer being freed was not allocated) but I fail to understand why it doesn't fail in the CASE_1 and fails in latter part of the sample code.
Upvotes: 1
Views: 442
Reputation: 134396
First, let's review the behaviour of free()
. Quoting C11
, chapter §7.22.3.3
void free(void *ptr);
The
free
function causes the space pointed to byptr
to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call tofree
orrealloc
, the behavior is undefined.
Follow the two emphasized points.
NULL
, to free()
as many times as you want, they are valid calls (just to be ignored).free()
once.Here, after calling free()
with the pointer, we're explicitly setting the pointer to NULL
. That is why, calling free()
with the same pointer variable later, any number of time, is not an issue, at all.
C uses pass-by-value for function argument passing. That's why, When wrapped inside a function,
free(pp);
works as expected, (it passes the required pointer to free()
) but
pp = NULL;
is local to the function and that change is not reflected to the caller. Thereby, calling the function again causes double free, as now,
free()
NULL
is not reflected to the caller, hence the pointer is not set to NULLfree()
d pointer again.As already mentioned, this invokes undefined behavior.
Solution: You need to pass a pointer to the pointer as the argument of the called function safefree()
and from the called function, you can set the pointer value to NULL
to get it reflected in the caller. Something like
void safefree(void ** ptrToPtr)
{
free(*ptrToPtr);
*ptrToPtr= NULL;
}
and calling like
safefree (&ptrToBeFreed);
will do the job (mind the types there, anyways).
Upvotes: 5
Reputation: 6405
Aside from Jonathan's remark, if you do something that results in undefined behavior (free the pointer again), it results in undefined behavior (errors, crashes).
Doing the same thing in different contexts does not necessarily result in the same undefined behavior, it depends on implementation details; they are typically only known to the compiler developer, so they seem 'random' from the outside. Nothing much can be learned by analyzing random undefined behavior. It could for example be that the compile time affects the result..., or the spelling of the directory you work in... anything.
Upvotes: 1