ant2009
ant2009

Reputation: 22486

Allocating memory and freeing them. Should we set them to NULL?

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

Answers (4)

Mike
Mike

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:

  1. Free takes a pointer returned by a memory allocation function (NULL or valid)
  2. If it's NULL, nothing happens
  3. If it's a valid pointer it frees the memory

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:

  1. export MALLOC_CHECK_=0 to turn off malloc check and (possibly) let your program crash
  2. export MALLOC_CHECK_=1 you'll get the above warning message
  3. export MALLOC_CHECK_=2 Will call abort(1) and give you a back trace of your code
  4. export MALLOC_CHECK_=3 is just option 1|2 together

Upvotes: 2

hmjd
hmjd

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. NULLing 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. NULLing 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

Alok Save
Alok Save

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

Benoit Thiery
Benoit Thiery

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

Related Questions