24

In C and C++, Freeing a NULL pointer will result in nothing done.

Still, I see people saying that memory corruption can occur if you "free memory twice".

Is this true? What is going on under the hood when you free memory twice?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Vijay
  • 65,327
  • 90
  • 227
  • 319
  • 6
    No memory is freed when you free a null pointer. If you free a *non-null* pointer twice, memory is freed twice, and that is a problem. – jalf Mar 18 '10 at 14:02

9 Answers9

25
int *p = malloc(sizeof(int));
//value of p is now lets say 0x12345678

*p = 2;
free(p); //memory pointer is freed, but still value of p is 0x12345678
         //now, if you free again, you get a crash or undefined behavior.

So, after free ing the first time, you should do p = NULL , so if (by any chance), free(p) is called again, nothing will happen.

Here is why freeing memory twice is undefined: Why free crashes when called twice

Community
  • 1
  • 1
N 1.1
  • 12,418
  • 6
  • 43
  • 61
  • 7
    +1 for correctness of the answer, even if I disagree in setting the pointer to NULL right after, that could hide a standing bug (calling `free` the second time) and I'd rather have it fail hard and fast so that the bug can be handled than hidden. – David Rodríguez - dribeas Mar 18 '10 at 10:25
  • @David: I totally agree, if `free` is called twice on a pointer, it is a (somewhat) bad implementation. – N 1.1 Mar 18 '10 at 10:27
  • 1
    @David: That's a good strategy as long as you know how to debug 'free-twice' situations. If you don't, I'd rather nullify the pointer right after freeing and check it for nullness just before every `free` statement. – Janusz Lenar Mar 18 '10 at 10:32
  • @nvl: Yeah, that's why you call it a **bug** ;D – Janusz Lenar Mar 18 '10 at 10:34
  • @malleor: doing your way, if you nullify pointer right after freeing, there is no need to check before `free` statement – N 1.1 Mar 18 '10 at 10:34
  • 3
    @malleor: having the double free kill the application you know that a pointer you are considering to be valid is actually not valid, hidding it can lead to situations where you dereference a null pointer and operate on it, which is undefined behavior (and depending on the system might just silently provide incorrect results). Debugging a crash is always simpler than debugging an incorrect value. – David Rodríguez - dribeas Mar 18 '10 at 11:00
  • @nvl: there is, if you want to find the bug - you're freeing twice! that was David's point. – Janusz Lenar Mar 18 '10 at 11:12
  • @malleor: well, i would go by "debugging the crash" way. – N 1.1 Mar 18 '10 at 11:18
  • @David: well, i disagree, but that's a matter of preference. i prefer debugging online, e.g. after debug break inside CRT assertion, i.e. `_ASSERTE(ptr!=NULL)`. – Janusz Lenar Mar 18 '10 at 11:21
  • 7
    @David: It's a tradeoff. I think leaving the pointer pointing to freed memory makes it more likely to hide errors where the pointer is used afterward, as dereferencing the null pointer is often more likely to crash. Double-freeing is undefined behavior as well, and it often won't lead to an immediate crash either. – jamesdlin Mar 18 '10 at 17:07
  • Setting p to NULL after freeing doesn't help with any of the other n pointers to that data you also had hanging around. So you still need to know how to debug a double-free. – Vicky Mar 31 '10 at 16:21
  • @N 1.1: _if free is called twice, it is bad_ This isn't true. Imagine a kernel module that could be removed while initializing, or an object of a class being deleted from another thread (because the program is quiting) while it is still in the middle of initialization. In these cases, you may have temporary memory that needs to be cleaned up. This cleaning happens after initialization is done, but also needs to be done upon removing/deletion (because initialization may have been interrupted). Therefore, free needs to be called for the same memory twice. Hence, the set to `'\0'` solution. – Shahbaz Aug 26 '11 at 15:39
  • @JanuszLenar I frankly don't understand why people are so fuzzy about setting this stupid pointer to NULL. In most situations it will go out of scope right after the `free()`/`delete`. Setting it to null between a `free()` and its passing into nonexistence is pretty pointless. And in those cases where the pointer does remain alive, you most likely need to set it to `NULL` anyway to signal that the memory doesn't exist anymore. So, this entire issue seems to get way more attention than it deserves. – cmaster - reinstate monica Jun 13 '14 at 21:11
  • @cmaster Agreed. This is why the discussion was dead for a couple of years. Cheers, mate. – Janusz Lenar Jun 16 '14 at 11:10
21

Freeing memory does not set the pointer to null. The pointer remains pointing to the memory it used to own, but which has now had ownership transferred back to the heap manager.

The heap manager may have since reallocated the memory your stale pointer is pointing to.

Freeing it again is not the same as saying free(NULL), and will result in undefined behavior.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
10

This is undefined behavior, that can result in heap corruption or other severe consequences.

free() for a null pointer simply checks the pointer value inside and returns. That check will not help against freeing a block twice.

Here's what happens usually. The heap implementation gets the address and tries to "take ownership" of the block at that address by modifying its own service data. Depending on the heap implementation anything can happen. Maybe it works and nothing happens, maybe the service data is corrupted and you've got heap corruption.

So don't do it. It's undefined behavior. Whatever bad things can happen.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 1
    I would also say explicitly that `free` ing a pointer doesn't (neceaarily) change it's value and in general it's not null after the 'free' (which is why the second `free` causes corruption). – Ari Mar 18 '10 at 10:18
5

To avoid free twice i alway using MACRO for free memory:

#ifdef FREEIF
# undef FREEIF
#endif
#define FREEIF( _p )  \
if( _p )              \
{                     \
        free( _p );   \
        _p = NULL;    \
}

this macro set p = NULL to avoid dangling pointer.

NguyenDat
  • 4,129
  • 3
  • 46
  • 46
  • 2
    This is a nice hack but I'd rather try to fix the actual cause. If free() get called twice on the same variable, this is clearly a bug. – user206268 Mar 25 '10 at 16:23
4

Yes, "undefined behavior" which almost always results in a crash. (while "undefined behavior" by definition means "anything", various types of errors often behave in quite predictable ways. In case of free(), the behavior is invariably segfault or respective "memory protection error" characteristic to the OS.)

Same if you free() a pointer to anything else than NULL or something you malloc'd.

char x; char* p=&x; free(p); // crash.

SF.
  • 13,549
  • 14
  • 71
  • 107
  • 3
    You are too optimistic on the results of undefined behavior. –  Mar 18 '10 at 10:19
  • 1
    I'm with Roger. In fact, freeing something twice almost never results in a crash at the point the free takes place, which makes it one of the most difficult bugs to track down. –  Mar 18 '10 at 10:41
4

When you call free on a pointer, your pointer will not get set to NULL. The free space is only given back to a pool to be available for allocation again. Here an example to test:

#include <stdio.h>
#include <stdlib.h>

int main(){
    int* ptr = (int*)malloc(sizeof(int));
    printf("Address before free: %p\n", ptr);
    free(ptr);
    printf("Address after free: %p\n", ptr);
    return 0;
}

This program outputs for me:

Address before free: 0x950a008
Address after free: 0x950a008

and you can see, that free did nothing to the pointer, but only told the system that the memory is available for reuse.

Lucas
  • 13,679
  • 13
  • 62
  • 94
3

free() 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 behaviour occurs. If ptr is NULL, no operation is performed.

So, you get undefined behavior, and anything could happen.

nos
  • 223,662
  • 58
  • 417
  • 506
1

1) Handling of dynamic memory is not done by compiler. There are run-time libraries which take care of this. For eg. : glibc provides APIs like malloc and free, which internally make system calls(sys_brk) to handle the heap area.

2) Freeing same memory twice refers to a condition like this : Suppose you have char *cptr;

You allocate memory using : cptr = (char *) malloc (SIZE);

Now, when you no longer need this memory, you can free it using this : free(cptr);

Now here what happens is the memory pointed to by cptr is free for use.

Suppose at a later point of time in the program you again call a free(cptr), then this is not a valid condition. This scenario where you are freeing the same memory twice is know as "freeing a memory twice" problem.`

Furquan
  • 676
  • 3
  • 5
0

Freeing memory more than once can have bad consequences. You can run this piece of code to see what may happen for your computer.

#include <stdio.h>      /* printf, scanf, NULL */
#include <stdlib.h>     /* malloc, free, rand */

int main ()


  {
  int i,n;
  char * buffer;

  printf ("How long do you want the string? ");
  scanf ("%d", &i);

  buffer = (char*) malloc (i+1);
  if (buffer==NULL) exit (1);

  for (n=0; n<i; n++)
          buffer[n]=rand()%26+'a';
  buffer[i]='\0';

  printf ("Random string: %s\n",buffer);
  free (buffer);
  free (buffer);

  return 0;
}

Many standard libraries like CSparse use a wrapper function that handles memory issues. I copied the function here:

 /* wrapper for free */
    void *cs_free (void *p)
    {
        if (p) free (p) ;       /* free p if it is not already NULL */
        return (NULL) ;         /* return NULL to simplify the use of    

    }

This function can handle the issues with memory. Please note that you have to take care of the condition that malloc returns NULL in some cases

Aznaveh
  • 558
  • 8
  • 27