Tuesday 8 November 2011

What happens if you free a pointer twice? in C programming

What happens if you free a pointer twice?

If you free a pointer, use it to allocate memory again, and free it again, of course it’s safe.

NOTE
To be precise and accurate, the pointed-to memory, not the pointer itself, has been freed. Nothing about the pointer has changed. However, C programmers in a hurry (that’s all of us, right?) will talk about “a freed pointer” to mean a pointer to freed memory.

If you free a pointer, the memory you freed might be reallocated. If that happens, you might get that pointer
back. In this case, freeing the pointer twice is OK, but only because you’ve been lucky. The following example
is silly, but safe:
#include <stdlib.h>
int
main(int argc, char** argv)
{
char** new_argv1;
char** new_argv2;
new_argv1 = calloc(argc+1, sizeof(char*));
free(new_argv1); /* freed once */
new_argv2 = (char**) calloc(argc+1, sizeof(char*));
if (new_argv1 == new_argv2) {
/*
new_argv1 accidentally points to freeable memory
*/
free(new_argv1); /* freed twice */
} else {
free(new_argv2);
}
new_argv1 = calloc(argc+1, sizeof(char*));
free(new_argv1); /* freed once again */
return 0;
}

In the preceding program, new_argv1 is pointed to a chunk of memory big enough to copy the argv array,
which is immediately freed. Then a chunk the same size is allocated, and its address is assigned to new_argv2.
Because the first chunk was available again, calloc might have returned it again; in that case, new_argv1 and
new_argv2 have the same value, and it doesn’t matter which variable you use. (Remember, it’s the pointedto
memory that’s freed, not the pointer variable.) Just for fun, new_argv1 is pointed to allocated memory
again, which is again freed. You can free a pointer as many times as you want; it’s the memory you have to
be careful about.
What if you free allocated memory, don’t get it allocated back to you, and then free it again? Something like
this:
void caller( ... )
{
void *p;
/* ... */
callee( p );
free( p );
}
void callee( void* p )
{
/* ... */
free( p );
return;
}

In this example, the caller() function is passing p to the callee() function and then freeing p. Unfortunately, callee() is also freeing p. Thus, the memory that p points to is being freed twice. The ANSI/ ISO C standard says this is undefined. Anything can happen. Usually, something very bad happens. The memory allocation and deallocation functions could be written to keep track of what has been used and what has been freed. Typically, they aren’t. If you free() a pointer, the pointed-to memory is assumed to have been allocated by malloc() or calloc() but not deallocated since then. free() calculates how big that chunk of memory was (see FAQ VII.26) and updates the data structures in the memory “arena.” Even if the memory has been freed already, free() will assume that it wasn’t, and it will blindly update the arena. This action is much faster than it would have been if free() had checked to see whether the pointer was OK todeallocate.

If something doesn’t work right, your program is now in trouble. When free() updates the arena, it will
probably write some information in a wrong place. You now have the fun of dealing with a wild pointer; see
the description at the beginning of the chapter.

How can you avoid double deallocation? Write your code carefully, use memory allocation tools, or
(preferably) do both.

Cross Reference:

VII.21: What is the heap?
VII.24: What is a “null pointer assignment” error? What are bus errors, memory faults, and core
dumps?
VII.26: How does free() know how much memory to release?

No comments:

Post a Comment