Reputation: 22486
gcc (GCC) 4.7.0
c89
Hello,
I am wondering if I am thinking correctly here. When I allocate memory using malloc. malloc will return a pointer to a size in memory.
So before I allocate my memory all pointers will have the value NULL.
Using this code snippet:
struct address *db_row = NULL;
db_row = malloc(sizeof(struct address));
db_row->name = malloc(sizeof(char) * 10);
db_row->email = malloc(sizeof(char) *10);
free(db_row->name);
free(db_row->email);
free(db_row);
I have done this in the gdb debugger for db_row before allocating memory:
(gdb) p db_row
$20 = (struct address *) 0x0
(gdb) p *db_row
Cannot access memory at address 0x0
Which is correct, as no memory address has been allocated. After I allocate memory I get the following when I do the same:
(gdb) p db_row
$25 = (struct address *) 0x602310
(gdb) p *db_row
$26 = {id = 0, set = 0, name = 0x0, email = 0x0}
However, after I have free the memory I still get the same memory address, should it not be NULL as in the first case before allocating any memory?
After freeing the memory:
(gdb) p db_row
$28 = (struct address *) 0x602310
(gdb) p *db_row
$27 = {id = 6300480, set = 0, name = 0x602330 "", email = 0x602350 " #`"}
As you can see its still pointing to the same memory location, is this correct?
Finally, I added this at the end to see if I could do a double free:
if(db_row != NULL) {
free(db_row);
}
if(db_row != NULL) {
free(db_row);
}
I get a stack dump on the second call to free. But as a safety measure should you always check to make sure you are not trying to do a double free?
It it worth setting the pointers to NULL after free them?
db_row = NULL;
Many thanks for any suggestions,
Upvotes: 3
Views: 1416
Reputation: 49373
To try to be clear here, I'm going to quote from the man page of malloc:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
So, to recap:
You'll note here it says nothing about changing the address that ptr
is pointing to. That's on you to do. So it's very safe to do:
int *p = malloc(sizeof(int));
*p = 5;
printf("p=%d\n",*p);
free(p);
p = NULL;
Now you can call free()
all day long on your pointer p and you're OK. If you're concerned about having errors with double free()
calls, on recent versions of Linux libc (later than 5.4.23) and GNU libc (2.x) there is a saftely mechanism in place called MALLOC_CHECK_
Instead of getting a stack crash you'll see a message such as:
*** glibc detected *** ./a.out: free(): invalid pointer: 0x0804b008 ***
You can use it in the following ways:
export MALLOC_CHECK_=0
to turn off malloc check and (possibly) let your program crashexport MALLOC_CHECK_=1
you'll get the above warning messageexport MALLOC_CHECK_=2
Will call abort(1) and give you a back trace of your codeexport MALLOC_CHECK_=3
is just option 1|2 togetherUpvotes: 2
Reputation: 121961
But as a safety measure should you always check to make sure you are not trying to free a NULL pointer?
Calling free()
with a NULL
pointer is safe and nothing occurs. Calling free()
does not NULL
the pointer, you may do this explicitly. NULL
ing a pointer after calling free()
would prevent the double free on the same pointer variable:
/* Assuming 'db_row' is referring to a valid address
at this stage the following code will not result
in a double free.*/
free(db_row);
db_row = NULL;
free(db_row);
If another pointer variable is pointing to the same address and is passed to free()
then a double free still occurs.
Just because a pointer is not-NULL
does not guarantee that it points to a valid address. It is the programmer's responsibility to ensure double free()
s do not occur. NULL
ing pointer variables after a call to free()
helps but does not provide a guarantee as multiple pointer variables can be pointing at the same address.
But as a safety measure should you always check to make sure you are not trying to do a double free?
There is no way to query a pointer variable to determine if the memory at the address that it holds has already been free()
d. A pointer variable holds an address, nothing more.
Upvotes: 5
Reputation: 206518
After I have free the memory I still get the same memory address, should it not be NULL as in the first case before allocating any memory?
Because free()
only releases the memory that was allocated to you. It dos not set the pointer to NULL
.
But as a safety measure should you always check to make sure you are not trying to free a NULL pointer?
If pointer passed to free()
is a null pointer, then no action occurs(C99 section 7.20.3.2).
It it worth setting the pointers to
NULL
after free them?
There is absolutely no merit in doing so, more often it would end up hiding your problems which will raise their ugly head in some or other form.
It is a defensive and dubious style of programming to avoid dangling pointers or double free problems, wherein you try to safeguard yourself against free()
getting called on the same pointer.In reality more often or not the double free problem occurs when you different pointers to the same memory and these different pointers are passed to free()
.
The practice of making the pointer NULL
does nothing in the second and more common bug scenario. All of these situations can only be avoided by writing programs by putting in some good thought and periodic code reviews.
Upvotes: 2
Reputation: 6387
It is good practice to set a pointer to null
after freeing it unless you are at the end of the scope of the variable; and yes it is normal that free
does not do that.
If the pointer is null
, calling free
on it is safe, and any access to it will generate a core dump, which is much easier to debug than memory corruption or double free
that could occur if you use a freed pointer not set to null
.
Upvotes: 3